199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2018 Vladimir Medvedkin <medvedkinv@gmail.com> 399a2dd95SBruce Richardson * Copyright(c) 2019 Intel Corporation 499a2dd95SBruce Richardson */ 599a2dd95SBruce Richardson 699a2dd95SBruce Richardson #include <stdint.h> 799a2dd95SBruce Richardson #include <stdio.h> 899a2dd95SBruce Richardson 999a2dd95SBruce Richardson #include <rte_debug.h> 1099a2dd95SBruce Richardson #include <rte_malloc.h> 1199a2dd95SBruce Richardson #include <rte_errno.h> 1299a2dd95SBruce Richardson #include <rte_vect.h> 1399a2dd95SBruce Richardson 1499a2dd95SBruce Richardson #include <rte_rib.h> 1599a2dd95SBruce Richardson #include <rte_fib.h> 1699a2dd95SBruce Richardson #include "dir24_8.h" 1796c3d06aSVladimir Medvedkin #include "fib_log.h" 1899a2dd95SBruce Richardson 1999a2dd95SBruce Richardson #ifdef CC_DIR24_8_AVX512_SUPPORT 2099a2dd95SBruce Richardson 2199a2dd95SBruce Richardson #include "dir24_8_avx512.h" 2299a2dd95SBruce Richardson 2399a2dd95SBruce Richardson #endif /* CC_DIR24_8_AVX512_SUPPORT */ 2499a2dd95SBruce Richardson 2599a2dd95SBruce Richardson #define DIR24_8_NAMESIZE 64 2699a2dd95SBruce Richardson 2799a2dd95SBruce Richardson #define ROUNDUP(x, y) RTE_ALIGN_CEIL(x, (1 << (32 - y))) 2899a2dd95SBruce Richardson 2999a2dd95SBruce Richardson static inline rte_fib_lookup_fn_t 30e194f3cdSVladimir Medvedkin get_scalar_fn(enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr) 3199a2dd95SBruce Richardson { 3299a2dd95SBruce Richardson switch (nh_sz) { 3399a2dd95SBruce Richardson case RTE_FIB_DIR24_8_1B: 34e194f3cdSVladimir Medvedkin return be_addr ? dir24_8_lookup_bulk_1b_be : dir24_8_lookup_bulk_1b; 3599a2dd95SBruce Richardson case RTE_FIB_DIR24_8_2B: 36e194f3cdSVladimir Medvedkin return be_addr ? dir24_8_lookup_bulk_2b_be : dir24_8_lookup_bulk_2b; 3799a2dd95SBruce Richardson case RTE_FIB_DIR24_8_4B: 38e194f3cdSVladimir Medvedkin return be_addr ? dir24_8_lookup_bulk_4b_be : dir24_8_lookup_bulk_4b; 3999a2dd95SBruce Richardson case RTE_FIB_DIR24_8_8B: 40e194f3cdSVladimir Medvedkin return be_addr ? dir24_8_lookup_bulk_8b_be : dir24_8_lookup_bulk_8b; 4199a2dd95SBruce Richardson default: 4299a2dd95SBruce Richardson return NULL; 4399a2dd95SBruce Richardson } 4499a2dd95SBruce Richardson } 4599a2dd95SBruce Richardson 4699a2dd95SBruce Richardson static inline rte_fib_lookup_fn_t 47e194f3cdSVladimir Medvedkin get_scalar_fn_inlined(enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr) 4899a2dd95SBruce Richardson { 4999a2dd95SBruce Richardson switch (nh_sz) { 5099a2dd95SBruce Richardson case RTE_FIB_DIR24_8_1B: 51e194f3cdSVladimir Medvedkin return be_addr ? dir24_8_lookup_bulk_0_be : dir24_8_lookup_bulk_0; 5299a2dd95SBruce Richardson case RTE_FIB_DIR24_8_2B: 53e194f3cdSVladimir Medvedkin return be_addr ? dir24_8_lookup_bulk_1_be : dir24_8_lookup_bulk_1; 5499a2dd95SBruce Richardson case RTE_FIB_DIR24_8_4B: 55e194f3cdSVladimir Medvedkin return be_addr ? dir24_8_lookup_bulk_2_be : dir24_8_lookup_bulk_2; 5699a2dd95SBruce Richardson case RTE_FIB_DIR24_8_8B: 57e194f3cdSVladimir Medvedkin return be_addr ? dir24_8_lookup_bulk_3_be : dir24_8_lookup_bulk_3; 5899a2dd95SBruce Richardson default: 5999a2dd95SBruce Richardson return NULL; 6099a2dd95SBruce Richardson } 6199a2dd95SBruce Richardson } 6299a2dd95SBruce Richardson 6399a2dd95SBruce Richardson static inline rte_fib_lookup_fn_t 64e194f3cdSVladimir Medvedkin get_vector_fn(enum rte_fib_dir24_8_nh_sz nh_sz, bool be_addr) 6599a2dd95SBruce Richardson { 6699a2dd95SBruce Richardson #ifdef CC_DIR24_8_AVX512_SUPPORT 67e194f3cdSVladimir Medvedkin if (rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512F) <= 0 || 68e194f3cdSVladimir Medvedkin rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512DQ) <= 0 || 69e194f3cdSVladimir Medvedkin rte_vect_get_max_simd_bitwidth() < RTE_VECT_SIMD_512) 70e194f3cdSVladimir Medvedkin return NULL; 71e194f3cdSVladimir Medvedkin 72e194f3cdSVladimir Medvedkin if (be_addr && rte_cpu_get_flag_enabled(RTE_CPUFLAG_AVX512BW) <= 0) 7399a2dd95SBruce Richardson return NULL; 7499a2dd95SBruce Richardson 7599a2dd95SBruce Richardson switch (nh_sz) { 7699a2dd95SBruce Richardson case RTE_FIB_DIR24_8_1B: 77e194f3cdSVladimir Medvedkin return be_addr ? rte_dir24_8_vec_lookup_bulk_1b_be : 78e194f3cdSVladimir Medvedkin rte_dir24_8_vec_lookup_bulk_1b; 7999a2dd95SBruce Richardson case RTE_FIB_DIR24_8_2B: 80e194f3cdSVladimir Medvedkin return be_addr ? rte_dir24_8_vec_lookup_bulk_2b_be : 81e194f3cdSVladimir Medvedkin rte_dir24_8_vec_lookup_bulk_2b; 8299a2dd95SBruce Richardson case RTE_FIB_DIR24_8_4B: 83e194f3cdSVladimir Medvedkin return be_addr ? rte_dir24_8_vec_lookup_bulk_4b_be : 84e194f3cdSVladimir Medvedkin rte_dir24_8_vec_lookup_bulk_4b; 8599a2dd95SBruce Richardson case RTE_FIB_DIR24_8_8B: 86e194f3cdSVladimir Medvedkin return be_addr ? rte_dir24_8_vec_lookup_bulk_8b_be : 87e194f3cdSVladimir Medvedkin rte_dir24_8_vec_lookup_bulk_8b; 8899a2dd95SBruce Richardson default: 8999a2dd95SBruce Richardson return NULL; 9099a2dd95SBruce Richardson } 9199a2dd95SBruce Richardson #else 9299a2dd95SBruce Richardson RTE_SET_USED(nh_sz); 93e194f3cdSVladimir Medvedkin RTE_SET_USED(be_addr); 9499a2dd95SBruce Richardson #endif 9599a2dd95SBruce Richardson return NULL; 9699a2dd95SBruce Richardson } 9799a2dd95SBruce Richardson 9899a2dd95SBruce Richardson rte_fib_lookup_fn_t 99e194f3cdSVladimir Medvedkin dir24_8_get_lookup_fn(void *p, enum rte_fib_lookup_type type, bool be_addr) 10099a2dd95SBruce Richardson { 10199a2dd95SBruce Richardson enum rte_fib_dir24_8_nh_sz nh_sz; 10299a2dd95SBruce Richardson rte_fib_lookup_fn_t ret_fn; 10399a2dd95SBruce Richardson struct dir24_8_tbl *dp = p; 10499a2dd95SBruce Richardson 10599a2dd95SBruce Richardson if (dp == NULL) 10699a2dd95SBruce Richardson return NULL; 10799a2dd95SBruce Richardson 10899a2dd95SBruce Richardson nh_sz = dp->nh_sz; 10999a2dd95SBruce Richardson 11099a2dd95SBruce Richardson switch (type) { 11199a2dd95SBruce Richardson case RTE_FIB_LOOKUP_DIR24_8_SCALAR_MACRO: 112e194f3cdSVladimir Medvedkin return get_scalar_fn(nh_sz, be_addr); 11399a2dd95SBruce Richardson case RTE_FIB_LOOKUP_DIR24_8_SCALAR_INLINE: 114e194f3cdSVladimir Medvedkin return get_scalar_fn_inlined(nh_sz, be_addr); 11599a2dd95SBruce Richardson case RTE_FIB_LOOKUP_DIR24_8_SCALAR_UNI: 116e194f3cdSVladimir Medvedkin return be_addr ? dir24_8_lookup_bulk_uni_be : dir24_8_lookup_bulk_uni; 11799a2dd95SBruce Richardson case RTE_FIB_LOOKUP_DIR24_8_VECTOR_AVX512: 118e194f3cdSVladimir Medvedkin return get_vector_fn(nh_sz, be_addr); 11999a2dd95SBruce Richardson case RTE_FIB_LOOKUP_DEFAULT: 120e194f3cdSVladimir Medvedkin ret_fn = get_vector_fn(nh_sz, be_addr); 121e194f3cdSVladimir Medvedkin return ret_fn != NULL ? ret_fn : get_scalar_fn(nh_sz, be_addr); 12299a2dd95SBruce Richardson default: 12399a2dd95SBruce Richardson return NULL; 12499a2dd95SBruce Richardson } 12599a2dd95SBruce Richardson 12699a2dd95SBruce Richardson return NULL; 12799a2dd95SBruce Richardson } 12899a2dd95SBruce Richardson 12999a2dd95SBruce Richardson static void 13099a2dd95SBruce Richardson write_to_fib(void *ptr, uint64_t val, enum rte_fib_dir24_8_nh_sz size, int n) 13199a2dd95SBruce Richardson { 13299a2dd95SBruce Richardson int i; 13399a2dd95SBruce Richardson uint8_t *ptr8 = (uint8_t *)ptr; 13499a2dd95SBruce Richardson uint16_t *ptr16 = (uint16_t *)ptr; 13599a2dd95SBruce Richardson uint32_t *ptr32 = (uint32_t *)ptr; 13699a2dd95SBruce Richardson uint64_t *ptr64 = (uint64_t *)ptr; 13799a2dd95SBruce Richardson 13899a2dd95SBruce Richardson switch (size) { 13999a2dd95SBruce Richardson case RTE_FIB_DIR24_8_1B: 14099a2dd95SBruce Richardson for (i = 0; i < n; i++) 14199a2dd95SBruce Richardson ptr8[i] = (uint8_t)val; 14299a2dd95SBruce Richardson break; 14399a2dd95SBruce Richardson case RTE_FIB_DIR24_8_2B: 14499a2dd95SBruce Richardson for (i = 0; i < n; i++) 14599a2dd95SBruce Richardson ptr16[i] = (uint16_t)val; 14699a2dd95SBruce Richardson break; 14799a2dd95SBruce Richardson case RTE_FIB_DIR24_8_4B: 14899a2dd95SBruce Richardson for (i = 0; i < n; i++) 14999a2dd95SBruce Richardson ptr32[i] = (uint32_t)val; 15099a2dd95SBruce Richardson break; 15199a2dd95SBruce Richardson case RTE_FIB_DIR24_8_8B: 15299a2dd95SBruce Richardson for (i = 0; i < n; i++) 15399a2dd95SBruce Richardson ptr64[i] = (uint64_t)val; 15499a2dd95SBruce Richardson break; 15599a2dd95SBruce Richardson } 15699a2dd95SBruce Richardson } 15799a2dd95SBruce Richardson 15899a2dd95SBruce Richardson static int 15999a2dd95SBruce Richardson tbl8_get_idx(struct dir24_8_tbl *dp) 16099a2dd95SBruce Richardson { 16199a2dd95SBruce Richardson uint32_t i; 16299a2dd95SBruce Richardson int bit_idx; 16399a2dd95SBruce Richardson 16499a2dd95SBruce Richardson for (i = 0; (i < (dp->number_tbl8s >> BITMAP_SLAB_BIT_SIZE_LOG2)) && 16599a2dd95SBruce Richardson (dp->tbl8_idxes[i] == UINT64_MAX); i++) 16699a2dd95SBruce Richardson ; 16799a2dd95SBruce Richardson if (i < (dp->number_tbl8s >> BITMAP_SLAB_BIT_SIZE_LOG2)) { 1683d4e27fdSDavid Marchand bit_idx = rte_ctz64(~dp->tbl8_idxes[i]); 16999a2dd95SBruce Richardson dp->tbl8_idxes[i] |= (1ULL << bit_idx); 17099a2dd95SBruce Richardson return (i << BITMAP_SLAB_BIT_SIZE_LOG2) + bit_idx; 17199a2dd95SBruce Richardson } 17299a2dd95SBruce Richardson return -ENOSPC; 17399a2dd95SBruce Richardson } 17499a2dd95SBruce Richardson 17599a2dd95SBruce Richardson static inline void 17699a2dd95SBruce Richardson tbl8_free_idx(struct dir24_8_tbl *dp, int idx) 17799a2dd95SBruce Richardson { 17899a2dd95SBruce Richardson dp->tbl8_idxes[idx >> BITMAP_SLAB_BIT_SIZE_LOG2] &= 17999a2dd95SBruce Richardson ~(1ULL << (idx & BITMAP_SLAB_BITMASK)); 18099a2dd95SBruce Richardson } 18199a2dd95SBruce Richardson 18299a2dd95SBruce Richardson static int 18399a2dd95SBruce Richardson tbl8_alloc(struct dir24_8_tbl *dp, uint64_t nh) 18499a2dd95SBruce Richardson { 18599a2dd95SBruce Richardson int64_t tbl8_idx; 18699a2dd95SBruce Richardson uint8_t *tbl8_ptr; 18799a2dd95SBruce Richardson 18899a2dd95SBruce Richardson tbl8_idx = tbl8_get_idx(dp); 18996c3d06aSVladimir Medvedkin 19096c3d06aSVladimir Medvedkin /* If there are no tbl8 groups try to reclaim one. */ 19196c3d06aSVladimir Medvedkin if (unlikely(tbl8_idx == -ENOSPC && dp->dq && 19296c3d06aSVladimir Medvedkin !rte_rcu_qsbr_dq_reclaim(dp->dq, 1, NULL, NULL, NULL))) 19396c3d06aSVladimir Medvedkin tbl8_idx = tbl8_get_idx(dp); 19496c3d06aSVladimir Medvedkin 19599a2dd95SBruce Richardson if (tbl8_idx < 0) 19699a2dd95SBruce Richardson return tbl8_idx; 19799a2dd95SBruce Richardson tbl8_ptr = (uint8_t *)dp->tbl8 + 19899a2dd95SBruce Richardson ((tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT) << 19999a2dd95SBruce Richardson dp->nh_sz); 20099a2dd95SBruce Richardson /*Init tbl8 entries with nexthop from tbl24*/ 20199a2dd95SBruce Richardson write_to_fib((void *)tbl8_ptr, nh| 20299a2dd95SBruce Richardson DIR24_8_EXT_ENT, dp->nh_sz, 20399a2dd95SBruce Richardson DIR24_8_TBL8_GRP_NUM_ENT); 20499a2dd95SBruce Richardson dp->cur_tbl8s++; 20599a2dd95SBruce Richardson return tbl8_idx; 20699a2dd95SBruce Richardson } 20799a2dd95SBruce Richardson 20899a2dd95SBruce Richardson static void 20996c3d06aSVladimir Medvedkin tbl8_cleanup_and_free(struct dir24_8_tbl *dp, uint64_t tbl8_idx) 21096c3d06aSVladimir Medvedkin { 21196c3d06aSVladimir Medvedkin uint8_t *ptr = (uint8_t *)dp->tbl8 + (tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT << dp->nh_sz); 21296c3d06aSVladimir Medvedkin 21396c3d06aSVladimir Medvedkin memset(ptr, 0, DIR24_8_TBL8_GRP_NUM_ENT << dp->nh_sz); 21496c3d06aSVladimir Medvedkin tbl8_free_idx(dp, tbl8_idx); 21596c3d06aSVladimir Medvedkin dp->cur_tbl8s--; 21696c3d06aSVladimir Medvedkin } 21796c3d06aSVladimir Medvedkin 21896c3d06aSVladimir Medvedkin static void 21996c3d06aSVladimir Medvedkin __rcu_qsbr_free_resource(void *p, void *data, unsigned int n __rte_unused) 22096c3d06aSVladimir Medvedkin { 22196c3d06aSVladimir Medvedkin struct dir24_8_tbl *dp = p; 22296c3d06aSVladimir Medvedkin uint64_t tbl8_idx = *(uint64_t *)data; 22396c3d06aSVladimir Medvedkin 22496c3d06aSVladimir Medvedkin tbl8_cleanup_and_free(dp, tbl8_idx); 22596c3d06aSVladimir Medvedkin } 22696c3d06aSVladimir Medvedkin 22796c3d06aSVladimir Medvedkin static void 22899a2dd95SBruce Richardson tbl8_recycle(struct dir24_8_tbl *dp, uint32_t ip, uint64_t tbl8_idx) 22999a2dd95SBruce Richardson { 23099a2dd95SBruce Richardson uint32_t i; 23199a2dd95SBruce Richardson uint64_t nh; 23299a2dd95SBruce Richardson uint8_t *ptr8; 23399a2dd95SBruce Richardson uint16_t *ptr16; 23499a2dd95SBruce Richardson uint32_t *ptr32; 23599a2dd95SBruce Richardson uint64_t *ptr64; 23699a2dd95SBruce Richardson 23799a2dd95SBruce Richardson switch (dp->nh_sz) { 23899a2dd95SBruce Richardson case RTE_FIB_DIR24_8_1B: 23999a2dd95SBruce Richardson ptr8 = &((uint8_t *)dp->tbl8)[tbl8_idx * 24099a2dd95SBruce Richardson DIR24_8_TBL8_GRP_NUM_ENT]; 24199a2dd95SBruce Richardson nh = *ptr8; 24299a2dd95SBruce Richardson for (i = 1; i < DIR24_8_TBL8_GRP_NUM_ENT; i++) { 24399a2dd95SBruce Richardson if (nh != ptr8[i]) 24499a2dd95SBruce Richardson return; 24599a2dd95SBruce Richardson } 24699a2dd95SBruce Richardson ((uint8_t *)dp->tbl24)[ip >> 8] = 24799a2dd95SBruce Richardson nh & ~DIR24_8_EXT_ENT; 24899a2dd95SBruce Richardson break; 24999a2dd95SBruce Richardson case RTE_FIB_DIR24_8_2B: 25099a2dd95SBruce Richardson ptr16 = &((uint16_t *)dp->tbl8)[tbl8_idx * 25199a2dd95SBruce Richardson DIR24_8_TBL8_GRP_NUM_ENT]; 25299a2dd95SBruce Richardson nh = *ptr16; 25399a2dd95SBruce Richardson for (i = 1; i < DIR24_8_TBL8_GRP_NUM_ENT; i++) { 25499a2dd95SBruce Richardson if (nh != ptr16[i]) 25599a2dd95SBruce Richardson return; 25699a2dd95SBruce Richardson } 25799a2dd95SBruce Richardson ((uint16_t *)dp->tbl24)[ip >> 8] = 25899a2dd95SBruce Richardson nh & ~DIR24_8_EXT_ENT; 25999a2dd95SBruce Richardson break; 26099a2dd95SBruce Richardson case RTE_FIB_DIR24_8_4B: 26199a2dd95SBruce Richardson ptr32 = &((uint32_t *)dp->tbl8)[tbl8_idx * 26299a2dd95SBruce Richardson DIR24_8_TBL8_GRP_NUM_ENT]; 26399a2dd95SBruce Richardson nh = *ptr32; 26499a2dd95SBruce Richardson for (i = 1; i < DIR24_8_TBL8_GRP_NUM_ENT; i++) { 26599a2dd95SBruce Richardson if (nh != ptr32[i]) 26699a2dd95SBruce Richardson return; 26799a2dd95SBruce Richardson } 26899a2dd95SBruce Richardson ((uint32_t *)dp->tbl24)[ip >> 8] = 26999a2dd95SBruce Richardson nh & ~DIR24_8_EXT_ENT; 27099a2dd95SBruce Richardson break; 27199a2dd95SBruce Richardson case RTE_FIB_DIR24_8_8B: 27299a2dd95SBruce Richardson ptr64 = &((uint64_t *)dp->tbl8)[tbl8_idx * 27399a2dd95SBruce Richardson DIR24_8_TBL8_GRP_NUM_ENT]; 27499a2dd95SBruce Richardson nh = *ptr64; 27599a2dd95SBruce Richardson for (i = 1; i < DIR24_8_TBL8_GRP_NUM_ENT; i++) { 27699a2dd95SBruce Richardson if (nh != ptr64[i]) 27799a2dd95SBruce Richardson return; 27899a2dd95SBruce Richardson } 27999a2dd95SBruce Richardson ((uint64_t *)dp->tbl24)[ip >> 8] = 28099a2dd95SBruce Richardson nh & ~DIR24_8_EXT_ENT; 28199a2dd95SBruce Richardson break; 28299a2dd95SBruce Richardson } 28396c3d06aSVladimir Medvedkin 28496c3d06aSVladimir Medvedkin if (dp->v == NULL) { 28596c3d06aSVladimir Medvedkin tbl8_cleanup_and_free(dp, tbl8_idx); 28696c3d06aSVladimir Medvedkin } else if (dp->rcu_mode == RTE_FIB_QSBR_MODE_SYNC) { 28796c3d06aSVladimir Medvedkin rte_rcu_qsbr_synchronize(dp->v, RTE_QSBR_THRID_INVALID); 28896c3d06aSVladimir Medvedkin tbl8_cleanup_and_free(dp, tbl8_idx); 28996c3d06aSVladimir Medvedkin } else { /* RTE_FIB_QSBR_MODE_DQ */ 29096c3d06aSVladimir Medvedkin if (rte_rcu_qsbr_dq_enqueue(dp->dq, &tbl8_idx)) 29196c3d06aSVladimir Medvedkin FIB_LOG(ERR, "Failed to push QSBR FIFO"); 29296c3d06aSVladimir Medvedkin } 29399a2dd95SBruce Richardson } 29499a2dd95SBruce Richardson 29599a2dd95SBruce Richardson static int 29699a2dd95SBruce Richardson install_to_fib(struct dir24_8_tbl *dp, uint32_t ledge, uint32_t redge, 29799a2dd95SBruce Richardson uint64_t next_hop) 29899a2dd95SBruce Richardson { 29999a2dd95SBruce Richardson uint64_t tbl24_tmp; 30099a2dd95SBruce Richardson int tbl8_idx; 30199a2dd95SBruce Richardson int tmp_tbl8_idx; 30299a2dd95SBruce Richardson uint8_t *tbl8_ptr; 30399a2dd95SBruce Richardson uint32_t len; 30499a2dd95SBruce Richardson 30599a2dd95SBruce Richardson len = ((ledge == 0) && (redge == 0)) ? 1 << 24 : 30699a2dd95SBruce Richardson ((redge & DIR24_8_TBL24_MASK) - ROUNDUP(ledge, 24)) >> 8; 30799a2dd95SBruce Richardson 30899a2dd95SBruce Richardson if (((ledge >> 8) != (redge >> 8)) || (len == 1 << 24)) { 30999a2dd95SBruce Richardson if ((ROUNDUP(ledge, 24) - ledge) != 0) { 31099a2dd95SBruce Richardson tbl24_tmp = get_tbl24(dp, ledge, dp->nh_sz); 31199a2dd95SBruce Richardson if ((tbl24_tmp & DIR24_8_EXT_ENT) != 31299a2dd95SBruce Richardson DIR24_8_EXT_ENT) { 31399a2dd95SBruce Richardson /** 31499a2dd95SBruce Richardson * Make sure there is space for two TBL8. 31599a2dd95SBruce Richardson * This is necessary when installing range that 31699a2dd95SBruce Richardson * needs tbl8 for ledge and redge. 31799a2dd95SBruce Richardson */ 31899a2dd95SBruce Richardson tbl8_idx = tbl8_alloc(dp, tbl24_tmp); 31999a2dd95SBruce Richardson tmp_tbl8_idx = tbl8_get_idx(dp); 32099a2dd95SBruce Richardson if (tbl8_idx < 0) 32199a2dd95SBruce Richardson return -ENOSPC; 32299a2dd95SBruce Richardson else if (tmp_tbl8_idx < 0) { 32399a2dd95SBruce Richardson tbl8_free_idx(dp, tbl8_idx); 32499a2dd95SBruce Richardson return -ENOSPC; 32599a2dd95SBruce Richardson } 32699a2dd95SBruce Richardson tbl8_free_idx(dp, tmp_tbl8_idx); 32799a2dd95SBruce Richardson /*update dir24 entry with tbl8 index*/ 32899a2dd95SBruce Richardson write_to_fib(get_tbl24_p(dp, ledge, 32999a2dd95SBruce Richardson dp->nh_sz), (tbl8_idx << 1)| 33099a2dd95SBruce Richardson DIR24_8_EXT_ENT, 33199a2dd95SBruce Richardson dp->nh_sz, 1); 33299a2dd95SBruce Richardson } else 33399a2dd95SBruce Richardson tbl8_idx = tbl24_tmp >> 1; 33499a2dd95SBruce Richardson tbl8_ptr = (uint8_t *)dp->tbl8 + 33599a2dd95SBruce Richardson (((tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT) + 33699a2dd95SBruce Richardson (ledge & ~DIR24_8_TBL24_MASK)) << 33799a2dd95SBruce Richardson dp->nh_sz); 33899a2dd95SBruce Richardson /*update tbl8 with new next hop*/ 33999a2dd95SBruce Richardson write_to_fib((void *)tbl8_ptr, (next_hop << 1)| 34099a2dd95SBruce Richardson DIR24_8_EXT_ENT, 34199a2dd95SBruce Richardson dp->nh_sz, ROUNDUP(ledge, 24) - ledge); 34299a2dd95SBruce Richardson tbl8_recycle(dp, ledge, tbl8_idx); 34399a2dd95SBruce Richardson } 34499a2dd95SBruce Richardson write_to_fib(get_tbl24_p(dp, ROUNDUP(ledge, 24), dp->nh_sz), 34599a2dd95SBruce Richardson next_hop << 1, dp->nh_sz, len); 34699a2dd95SBruce Richardson if (redge & ~DIR24_8_TBL24_MASK) { 34799a2dd95SBruce Richardson tbl24_tmp = get_tbl24(dp, redge, dp->nh_sz); 34899a2dd95SBruce Richardson if ((tbl24_tmp & DIR24_8_EXT_ENT) != 34999a2dd95SBruce Richardson DIR24_8_EXT_ENT) { 35099a2dd95SBruce Richardson tbl8_idx = tbl8_alloc(dp, tbl24_tmp); 35199a2dd95SBruce Richardson if (tbl8_idx < 0) 35299a2dd95SBruce Richardson return -ENOSPC; 35399a2dd95SBruce Richardson /*update dir24 entry with tbl8 index*/ 35499a2dd95SBruce Richardson write_to_fib(get_tbl24_p(dp, redge, 35599a2dd95SBruce Richardson dp->nh_sz), (tbl8_idx << 1)| 35699a2dd95SBruce Richardson DIR24_8_EXT_ENT, 35799a2dd95SBruce Richardson dp->nh_sz, 1); 35899a2dd95SBruce Richardson } else 35999a2dd95SBruce Richardson tbl8_idx = tbl24_tmp >> 1; 36099a2dd95SBruce Richardson tbl8_ptr = (uint8_t *)dp->tbl8 + 36199a2dd95SBruce Richardson ((tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT) << 36299a2dd95SBruce Richardson dp->nh_sz); 36399a2dd95SBruce Richardson /*update tbl8 with new next hop*/ 36499a2dd95SBruce Richardson write_to_fib((void *)tbl8_ptr, (next_hop << 1)| 36599a2dd95SBruce Richardson DIR24_8_EXT_ENT, 36699a2dd95SBruce Richardson dp->nh_sz, redge & ~DIR24_8_TBL24_MASK); 36799a2dd95SBruce Richardson tbl8_recycle(dp, redge, tbl8_idx); 36899a2dd95SBruce Richardson } 36999a2dd95SBruce Richardson } else if ((redge - ledge) != 0) { 37099a2dd95SBruce Richardson tbl24_tmp = get_tbl24(dp, ledge, dp->nh_sz); 37199a2dd95SBruce Richardson if ((tbl24_tmp & DIR24_8_EXT_ENT) != 37299a2dd95SBruce Richardson DIR24_8_EXT_ENT) { 37399a2dd95SBruce Richardson tbl8_idx = tbl8_alloc(dp, tbl24_tmp); 37499a2dd95SBruce Richardson if (tbl8_idx < 0) 37599a2dd95SBruce Richardson return -ENOSPC; 37699a2dd95SBruce Richardson /*update dir24 entry with tbl8 index*/ 37799a2dd95SBruce Richardson write_to_fib(get_tbl24_p(dp, ledge, dp->nh_sz), 37899a2dd95SBruce Richardson (tbl8_idx << 1)| 37999a2dd95SBruce Richardson DIR24_8_EXT_ENT, 38099a2dd95SBruce Richardson dp->nh_sz, 1); 38199a2dd95SBruce Richardson } else 38299a2dd95SBruce Richardson tbl8_idx = tbl24_tmp >> 1; 38399a2dd95SBruce Richardson tbl8_ptr = (uint8_t *)dp->tbl8 + 38499a2dd95SBruce Richardson (((tbl8_idx * DIR24_8_TBL8_GRP_NUM_ENT) + 38599a2dd95SBruce Richardson (ledge & ~DIR24_8_TBL24_MASK)) << 38699a2dd95SBruce Richardson dp->nh_sz); 38799a2dd95SBruce Richardson /*update tbl8 with new next hop*/ 38899a2dd95SBruce Richardson write_to_fib((void *)tbl8_ptr, (next_hop << 1)| 38999a2dd95SBruce Richardson DIR24_8_EXT_ENT, 39099a2dd95SBruce Richardson dp->nh_sz, redge - ledge); 39199a2dd95SBruce Richardson tbl8_recycle(dp, ledge, tbl8_idx); 39299a2dd95SBruce Richardson } 39399a2dd95SBruce Richardson return 0; 39499a2dd95SBruce Richardson } 39599a2dd95SBruce Richardson 39699a2dd95SBruce Richardson static int 39799a2dd95SBruce Richardson modify_fib(struct dir24_8_tbl *dp, struct rte_rib *rib, uint32_t ip, 39899a2dd95SBruce Richardson uint8_t depth, uint64_t next_hop) 39999a2dd95SBruce Richardson { 40099a2dd95SBruce Richardson struct rte_rib_node *tmp = NULL; 40199a2dd95SBruce Richardson uint32_t ledge, redge, tmp_ip; 40299a2dd95SBruce Richardson int ret; 40399a2dd95SBruce Richardson uint8_t tmp_depth; 40499a2dd95SBruce Richardson 40599a2dd95SBruce Richardson ledge = ip; 40699a2dd95SBruce Richardson do { 40799a2dd95SBruce Richardson tmp = rte_rib_get_nxt(rib, ip, depth, tmp, 40899a2dd95SBruce Richardson RTE_RIB_GET_NXT_COVER); 40999a2dd95SBruce Richardson if (tmp != NULL) { 41099a2dd95SBruce Richardson rte_rib_get_depth(tmp, &tmp_depth); 41199a2dd95SBruce Richardson if (tmp_depth == depth) 41299a2dd95SBruce Richardson continue; 41399a2dd95SBruce Richardson rte_rib_get_ip(tmp, &tmp_ip); 41499a2dd95SBruce Richardson redge = tmp_ip & rte_rib_depth_to_mask(tmp_depth); 41599a2dd95SBruce Richardson if (ledge == redge) { 41699a2dd95SBruce Richardson ledge = redge + 41799a2dd95SBruce Richardson (uint32_t)(1ULL << (32 - tmp_depth)); 41899a2dd95SBruce Richardson continue; 41999a2dd95SBruce Richardson } 42099a2dd95SBruce Richardson ret = install_to_fib(dp, ledge, redge, 42199a2dd95SBruce Richardson next_hop); 42299a2dd95SBruce Richardson if (ret != 0) 42399a2dd95SBruce Richardson return ret; 42499a2dd95SBruce Richardson ledge = redge + 42599a2dd95SBruce Richardson (uint32_t)(1ULL << (32 - tmp_depth)); 426ab1b927cSVladimir Medvedkin /* 427ab1b927cSVladimir Medvedkin * we got to the end of address space 428ab1b927cSVladimir Medvedkin * and wrapped around 429ab1b927cSVladimir Medvedkin */ 430ab1b927cSVladimir Medvedkin if (ledge == 0) 431ab1b927cSVladimir Medvedkin break; 43299a2dd95SBruce Richardson } else { 43399a2dd95SBruce Richardson redge = ip + (uint32_t)(1ULL << (32 - depth)); 434880bc2b5SVladimir Medvedkin if (ledge == redge && ledge != 0) 43599a2dd95SBruce Richardson break; 43699a2dd95SBruce Richardson ret = install_to_fib(dp, ledge, redge, 43799a2dd95SBruce Richardson next_hop); 43899a2dd95SBruce Richardson if (ret != 0) 43999a2dd95SBruce Richardson return ret; 44099a2dd95SBruce Richardson } 44199a2dd95SBruce Richardson } while (tmp); 44299a2dd95SBruce Richardson 44399a2dd95SBruce Richardson return 0; 44499a2dd95SBruce Richardson } 44599a2dd95SBruce Richardson 44699a2dd95SBruce Richardson int 44799a2dd95SBruce Richardson dir24_8_modify(struct rte_fib *fib, uint32_t ip, uint8_t depth, 44899a2dd95SBruce Richardson uint64_t next_hop, int op) 44999a2dd95SBruce Richardson { 45099a2dd95SBruce Richardson struct dir24_8_tbl *dp; 45199a2dd95SBruce Richardson struct rte_rib *rib; 45299a2dd95SBruce Richardson struct rte_rib_node *tmp = NULL; 45399a2dd95SBruce Richardson struct rte_rib_node *node; 45499a2dd95SBruce Richardson struct rte_rib_node *parent; 45599a2dd95SBruce Richardson int ret = 0; 45699a2dd95SBruce Richardson uint64_t par_nh, node_nh; 45799a2dd95SBruce Richardson 45899a2dd95SBruce Richardson if ((fib == NULL) || (depth > RTE_FIB_MAXDEPTH)) 45999a2dd95SBruce Richardson return -EINVAL; 46099a2dd95SBruce Richardson 46199a2dd95SBruce Richardson dp = rte_fib_get_dp(fib); 46299a2dd95SBruce Richardson rib = rte_fib_get_rib(fib); 46399a2dd95SBruce Richardson RTE_ASSERT((dp != NULL) && (rib != NULL)); 46499a2dd95SBruce Richardson 46599a2dd95SBruce Richardson if (next_hop > get_max_nh(dp->nh_sz)) 46699a2dd95SBruce Richardson return -EINVAL; 46799a2dd95SBruce Richardson 46899a2dd95SBruce Richardson ip &= rte_rib_depth_to_mask(depth); 46999a2dd95SBruce Richardson 47099a2dd95SBruce Richardson node = rte_rib_lookup_exact(rib, ip, depth); 47199a2dd95SBruce Richardson switch (op) { 47299a2dd95SBruce Richardson case RTE_FIB_ADD: 47399a2dd95SBruce Richardson if (node != NULL) { 47499a2dd95SBruce Richardson rte_rib_get_nh(node, &node_nh); 47599a2dd95SBruce Richardson if (node_nh == next_hop) 47699a2dd95SBruce Richardson return 0; 47799a2dd95SBruce Richardson ret = modify_fib(dp, rib, ip, depth, next_hop); 47899a2dd95SBruce Richardson if (ret == 0) 47999a2dd95SBruce Richardson rte_rib_set_nh(node, next_hop); 48099a2dd95SBruce Richardson return 0; 48199a2dd95SBruce Richardson } 48299a2dd95SBruce Richardson if (depth > 24) { 48399a2dd95SBruce Richardson tmp = rte_rib_get_nxt(rib, ip, 24, NULL, 48499a2dd95SBruce Richardson RTE_RIB_GET_NXT_COVER); 48599a2dd95SBruce Richardson if ((tmp == NULL) && 48699a2dd95SBruce Richardson (dp->rsvd_tbl8s >= dp->number_tbl8s)) 48799a2dd95SBruce Richardson return -ENOSPC; 48899a2dd95SBruce Richardson 48999a2dd95SBruce Richardson } 49099a2dd95SBruce Richardson node = rte_rib_insert(rib, ip, depth); 49199a2dd95SBruce Richardson if (node == NULL) 49299a2dd95SBruce Richardson return -rte_errno; 49399a2dd95SBruce Richardson rte_rib_set_nh(node, next_hop); 49499a2dd95SBruce Richardson parent = rte_rib_lookup_parent(node); 49599a2dd95SBruce Richardson if (parent != NULL) { 49699a2dd95SBruce Richardson rte_rib_get_nh(parent, &par_nh); 49799a2dd95SBruce Richardson if (par_nh == next_hop) 49899a2dd95SBruce Richardson return 0; 49999a2dd95SBruce Richardson } 50099a2dd95SBruce Richardson ret = modify_fib(dp, rib, ip, depth, next_hop); 50199a2dd95SBruce Richardson if (ret != 0) { 50299a2dd95SBruce Richardson rte_rib_remove(rib, ip, depth); 50399a2dd95SBruce Richardson return ret; 50499a2dd95SBruce Richardson } 50599a2dd95SBruce Richardson if ((depth > 24) && (tmp == NULL)) 50699a2dd95SBruce Richardson dp->rsvd_tbl8s++; 50799a2dd95SBruce Richardson return 0; 50899a2dd95SBruce Richardson case RTE_FIB_DEL: 50999a2dd95SBruce Richardson if (node == NULL) 51099a2dd95SBruce Richardson return -ENOENT; 51199a2dd95SBruce Richardson 51299a2dd95SBruce Richardson parent = rte_rib_lookup_parent(node); 51399a2dd95SBruce Richardson if (parent != NULL) { 51499a2dd95SBruce Richardson rte_rib_get_nh(parent, &par_nh); 51599a2dd95SBruce Richardson rte_rib_get_nh(node, &node_nh); 51699a2dd95SBruce Richardson if (par_nh != node_nh) 51799a2dd95SBruce Richardson ret = modify_fib(dp, rib, ip, depth, par_nh); 51899a2dd95SBruce Richardson } else 51999a2dd95SBruce Richardson ret = modify_fib(dp, rib, ip, depth, dp->def_nh); 52099a2dd95SBruce Richardson if (ret == 0) { 52199a2dd95SBruce Richardson rte_rib_remove(rib, ip, depth); 52299a2dd95SBruce Richardson if (depth > 24) { 52399a2dd95SBruce Richardson tmp = rte_rib_get_nxt(rib, ip, 24, NULL, 52499a2dd95SBruce Richardson RTE_RIB_GET_NXT_COVER); 52599a2dd95SBruce Richardson if (tmp == NULL) 52699a2dd95SBruce Richardson dp->rsvd_tbl8s--; 52799a2dd95SBruce Richardson } 52899a2dd95SBruce Richardson } 52999a2dd95SBruce Richardson return ret; 53099a2dd95SBruce Richardson default: 53199a2dd95SBruce Richardson break; 53299a2dd95SBruce Richardson } 53399a2dd95SBruce Richardson return -EINVAL; 53499a2dd95SBruce Richardson } 53599a2dd95SBruce Richardson 53699a2dd95SBruce Richardson void * 53799a2dd95SBruce Richardson dir24_8_create(const char *name, int socket_id, struct rte_fib_conf *fib_conf) 53899a2dd95SBruce Richardson { 53999a2dd95SBruce Richardson char mem_name[DIR24_8_NAMESIZE]; 54099a2dd95SBruce Richardson struct dir24_8_tbl *dp; 54199a2dd95SBruce Richardson uint64_t def_nh; 54299a2dd95SBruce Richardson uint32_t num_tbl8; 54399a2dd95SBruce Richardson enum rte_fib_dir24_8_nh_sz nh_sz; 54499a2dd95SBruce Richardson 54599a2dd95SBruce Richardson if ((name == NULL) || (fib_conf == NULL) || 54699a2dd95SBruce Richardson (fib_conf->dir24_8.nh_sz < RTE_FIB_DIR24_8_1B) || 54799a2dd95SBruce Richardson (fib_conf->dir24_8.nh_sz > RTE_FIB_DIR24_8_8B) || 54899a2dd95SBruce Richardson (fib_conf->dir24_8.num_tbl8 > 54999a2dd95SBruce Richardson get_max_nh(fib_conf->dir24_8.nh_sz)) || 55099a2dd95SBruce Richardson (fib_conf->dir24_8.num_tbl8 == 0) || 55199a2dd95SBruce Richardson (fib_conf->default_nh > 55299a2dd95SBruce Richardson get_max_nh(fib_conf->dir24_8.nh_sz))) { 55399a2dd95SBruce Richardson rte_errno = EINVAL; 55499a2dd95SBruce Richardson return NULL; 55599a2dd95SBruce Richardson } 55699a2dd95SBruce Richardson 55799a2dd95SBruce Richardson def_nh = fib_conf->default_nh; 55899a2dd95SBruce Richardson nh_sz = fib_conf->dir24_8.nh_sz; 55999a2dd95SBruce Richardson num_tbl8 = RTE_ALIGN_CEIL(fib_conf->dir24_8.num_tbl8, 56099a2dd95SBruce Richardson BITMAP_SLAB_BIT_SIZE); 56199a2dd95SBruce Richardson 56299a2dd95SBruce Richardson snprintf(mem_name, sizeof(mem_name), "DP_%s", name); 56399a2dd95SBruce Richardson dp = rte_zmalloc_socket(name, sizeof(struct dir24_8_tbl) + 56466ed1786SVladimir Medvedkin DIR24_8_TBL24_NUM_ENT * (1 << nh_sz) + sizeof(uint32_t), 56566ed1786SVladimir Medvedkin RTE_CACHE_LINE_SIZE, socket_id); 56699a2dd95SBruce Richardson if (dp == NULL) { 56799a2dd95SBruce Richardson rte_errno = ENOMEM; 56899a2dd95SBruce Richardson return NULL; 56999a2dd95SBruce Richardson } 57099a2dd95SBruce Richardson 57199a2dd95SBruce Richardson /* Init table with default value */ 57299a2dd95SBruce Richardson write_to_fib(dp->tbl24, (def_nh << 1), nh_sz, 1 << 24); 57399a2dd95SBruce Richardson 57499a2dd95SBruce Richardson snprintf(mem_name, sizeof(mem_name), "TBL8_%p", dp); 57599a2dd95SBruce Richardson uint64_t tbl8_sz = DIR24_8_TBL8_GRP_NUM_ENT * (1ULL << nh_sz) * 57699a2dd95SBruce Richardson (num_tbl8 + 1); 57799a2dd95SBruce Richardson dp->tbl8 = rte_zmalloc_socket(mem_name, tbl8_sz, 57899a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE, socket_id); 57999a2dd95SBruce Richardson if (dp->tbl8 == NULL) { 58099a2dd95SBruce Richardson rte_errno = ENOMEM; 58199a2dd95SBruce Richardson rte_free(dp); 58299a2dd95SBruce Richardson return NULL; 58399a2dd95SBruce Richardson } 58499a2dd95SBruce Richardson dp->def_nh = def_nh; 58599a2dd95SBruce Richardson dp->nh_sz = nh_sz; 58699a2dd95SBruce Richardson dp->number_tbl8s = num_tbl8; 58799a2dd95SBruce Richardson 58899a2dd95SBruce Richardson snprintf(mem_name, sizeof(mem_name), "TBL8_idxes_%p", dp); 58999a2dd95SBruce Richardson dp->tbl8_idxes = rte_zmalloc_socket(mem_name, 59099a2dd95SBruce Richardson RTE_ALIGN_CEIL(dp->number_tbl8s, 64) >> 3, 59199a2dd95SBruce Richardson RTE_CACHE_LINE_SIZE, socket_id); 59299a2dd95SBruce Richardson if (dp->tbl8_idxes == NULL) { 59399a2dd95SBruce Richardson rte_errno = ENOMEM; 59499a2dd95SBruce Richardson rte_free(dp->tbl8); 59599a2dd95SBruce Richardson rte_free(dp); 59699a2dd95SBruce Richardson return NULL; 59799a2dd95SBruce Richardson } 59899a2dd95SBruce Richardson 59999a2dd95SBruce Richardson return dp; 60099a2dd95SBruce Richardson } 60199a2dd95SBruce Richardson 60299a2dd95SBruce Richardson void 60399a2dd95SBruce Richardson dir24_8_free(void *p) 60499a2dd95SBruce Richardson { 60599a2dd95SBruce Richardson struct dir24_8_tbl *dp = (struct dir24_8_tbl *)p; 60699a2dd95SBruce Richardson 60796c3d06aSVladimir Medvedkin rte_rcu_qsbr_dq_delete(dp->dq); 60899a2dd95SBruce Richardson rte_free(dp->tbl8_idxes); 60999a2dd95SBruce Richardson rte_free(dp->tbl8); 61099a2dd95SBruce Richardson rte_free(dp); 61199a2dd95SBruce Richardson } 61296c3d06aSVladimir Medvedkin 61396c3d06aSVladimir Medvedkin int 61496c3d06aSVladimir Medvedkin dir24_8_rcu_qsbr_add(struct dir24_8_tbl *dp, struct rte_fib_rcu_config *cfg, 61596c3d06aSVladimir Medvedkin const char *name) 61696c3d06aSVladimir Medvedkin { 61796c3d06aSVladimir Medvedkin struct rte_rcu_qsbr_dq_parameters params = {0}; 61896c3d06aSVladimir Medvedkin char rcu_dq_name[RTE_RCU_QSBR_DQ_NAMESIZE]; 61996c3d06aSVladimir Medvedkin 620*cc8764c6SVladimir Medvedkin if (dp == NULL || cfg == NULL) 621*cc8764c6SVladimir Medvedkin return -EINVAL; 62296c3d06aSVladimir Medvedkin 623*cc8764c6SVladimir Medvedkin if (dp->v != NULL) 624*cc8764c6SVladimir Medvedkin return -EEXIST; 62596c3d06aSVladimir Medvedkin 62696c3d06aSVladimir Medvedkin if (cfg->mode == RTE_FIB_QSBR_MODE_SYNC) { 62796c3d06aSVladimir Medvedkin /* No other things to do. */ 62896c3d06aSVladimir Medvedkin } else if (cfg->mode == RTE_FIB_QSBR_MODE_DQ) { 62996c3d06aSVladimir Medvedkin /* Init QSBR defer queue. */ 63096c3d06aSVladimir Medvedkin snprintf(rcu_dq_name, sizeof(rcu_dq_name), 63196c3d06aSVladimir Medvedkin "FIB_RCU_%s", name); 63296c3d06aSVladimir Medvedkin params.name = rcu_dq_name; 63396c3d06aSVladimir Medvedkin params.size = cfg->dq_size; 63496c3d06aSVladimir Medvedkin if (params.size == 0) 63596c3d06aSVladimir Medvedkin params.size = RTE_FIB_RCU_DQ_RECLAIM_SZ; 63696c3d06aSVladimir Medvedkin params.trigger_reclaim_limit = cfg->reclaim_thd; 63796c3d06aSVladimir Medvedkin params.max_reclaim_size = cfg->reclaim_max; 63896c3d06aSVladimir Medvedkin if (params.max_reclaim_size == 0) 63996c3d06aSVladimir Medvedkin params.max_reclaim_size = RTE_FIB_RCU_DQ_RECLAIM_MAX; 64096c3d06aSVladimir Medvedkin params.esize = sizeof(uint64_t); 64196c3d06aSVladimir Medvedkin params.free_fn = __rcu_qsbr_free_resource; 64296c3d06aSVladimir Medvedkin params.p = dp; 64396c3d06aSVladimir Medvedkin params.v = cfg->v; 64496c3d06aSVladimir Medvedkin dp->dq = rte_rcu_qsbr_dq_create(¶ms); 64596c3d06aSVladimir Medvedkin if (dp->dq == NULL) { 64696c3d06aSVladimir Medvedkin FIB_LOG(ERR, "LPM defer queue creation failed"); 647*cc8764c6SVladimir Medvedkin return -rte_errno; 64896c3d06aSVladimir Medvedkin } 64996c3d06aSVladimir Medvedkin } else { 650*cc8764c6SVladimir Medvedkin return -EINVAL; 65196c3d06aSVladimir Medvedkin } 652*cc8764c6SVladimir Medvedkin 65396c3d06aSVladimir Medvedkin dp->rcu_mode = cfg->mode; 65496c3d06aSVladimir Medvedkin dp->v = cfg->v; 65596c3d06aSVladimir Medvedkin 65696c3d06aSVladimir Medvedkin return 0; 65796c3d06aSVladimir Medvedkin } 658