13a3e8931SAnoob Joseph /* SPDX-License-Identifier: BSD-3-Clause
23a3e8931SAnoob Joseph * Copyright(C) 2023 Marvell.
33a3e8931SAnoob Joseph */
43a3e8931SAnoob Joseph
537d39531SVolodymyr Fialko #include <rte_bitmap.h>
63a3e8931SAnoob Joseph #include <rte_pdcp.h>
73a3e8931SAnoob Joseph
83a3e8931SAnoob Joseph #include "pdcp_cnt.h"
937d39531SVolodymyr Fialko #include "pdcp_ctrl_pdu.h"
103a3e8931SAnoob Joseph #include "pdcp_entity.h"
113a3e8931SAnoob Joseph
1237d39531SVolodymyr Fialko #define SLAB_BYTE_SIZE (RTE_BITMAP_SLAB_BIT_SIZE / 8)
133a3e8931SAnoob Joseph
1437d39531SVolodymyr Fialko uint32_t
pdcp_cnt_bitmap_get_memory_footprint(const struct rte_pdcp_entity_conf * conf)1537d39531SVolodymyr Fialko pdcp_cnt_bitmap_get_memory_footprint(const struct rte_pdcp_entity_conf *conf)
1637d39531SVolodymyr Fialko {
1737d39531SVolodymyr Fialko uint32_t n_bits = pdcp_window_size_get(conf->pdcp_xfrm.sn_size);
1837d39531SVolodymyr Fialko
1937d39531SVolodymyr Fialko return rte_bitmap_get_memory_footprint(n_bits);
2037d39531SVolodymyr Fialko }
2137d39531SVolodymyr Fialko
2237d39531SVolodymyr Fialko int
pdcp_cnt_bitmap_create(struct entity_priv_dl_part * dl,uint32_t nb_elem,void * bitmap_mem,uint32_t mem_size)23*af42b2d1SVolodymyr Fialko pdcp_cnt_bitmap_create(struct entity_priv_dl_part *dl, uint32_t nb_elem,
24*af42b2d1SVolodymyr Fialko void *bitmap_mem, uint32_t mem_size)
2537d39531SVolodymyr Fialko {
26*af42b2d1SVolodymyr Fialko dl->bitmap.bmp = rte_bitmap_init(nb_elem, bitmap_mem, mem_size);
2737d39531SVolodymyr Fialko if (dl->bitmap.bmp == NULL)
283a3e8931SAnoob Joseph return -EINVAL;
293a3e8931SAnoob Joseph
30*af42b2d1SVolodymyr Fialko dl->bitmap.size = nb_elem;
313a3e8931SAnoob Joseph
323a3e8931SAnoob Joseph return 0;
333a3e8931SAnoob Joseph }
3437d39531SVolodymyr Fialko
3537d39531SVolodymyr Fialko void
pdcp_cnt_bitmap_set(struct pdcp_cnt_bitmap bitmap,uint32_t count)3637d39531SVolodymyr Fialko pdcp_cnt_bitmap_set(struct pdcp_cnt_bitmap bitmap, uint32_t count)
3737d39531SVolodymyr Fialko {
3837d39531SVolodymyr Fialko rte_bitmap_set(bitmap.bmp, count % bitmap.size);
3937d39531SVolodymyr Fialko }
4037d39531SVolodymyr Fialko
4137d39531SVolodymyr Fialko bool
pdcp_cnt_bitmap_is_set(struct pdcp_cnt_bitmap bitmap,uint32_t count)4237d39531SVolodymyr Fialko pdcp_cnt_bitmap_is_set(struct pdcp_cnt_bitmap bitmap, uint32_t count)
4337d39531SVolodymyr Fialko {
4437d39531SVolodymyr Fialko return rte_bitmap_get(bitmap.bmp, count % bitmap.size);
4537d39531SVolodymyr Fialko }
4637d39531SVolodymyr Fialko
4737d39531SVolodymyr Fialko void
pdcp_cnt_bitmap_range_clear(struct pdcp_cnt_bitmap bitmap,uint32_t start,uint32_t stop)4837d39531SVolodymyr Fialko pdcp_cnt_bitmap_range_clear(struct pdcp_cnt_bitmap bitmap, uint32_t start, uint32_t stop)
4937d39531SVolodymyr Fialko {
5037d39531SVolodymyr Fialko uint32_t i;
5137d39531SVolodymyr Fialko
5237d39531SVolodymyr Fialko for (i = start; i < stop; i++)
5337d39531SVolodymyr Fialko rte_bitmap_clear(bitmap.bmp, i % bitmap.size);
5437d39531SVolodymyr Fialko }
5537d39531SVolodymyr Fialko
5637d39531SVolodymyr Fialko uint16_t
pdcp_cnt_get_bitmap_size(uint32_t pending_bytes)5737d39531SVolodymyr Fialko pdcp_cnt_get_bitmap_size(uint32_t pending_bytes)
5837d39531SVolodymyr Fialko {
5937d39531SVolodymyr Fialko /*
6037d39531SVolodymyr Fialko * Round up bitmap size to slab size to operate only on slabs sizes, instead of individual
6137d39531SVolodymyr Fialko * bytes
6237d39531SVolodymyr Fialko */
6337d39531SVolodymyr Fialko return RTE_ALIGN_MUL_CEIL(pending_bytes, SLAB_BYTE_SIZE);
6437d39531SVolodymyr Fialko }
6537d39531SVolodymyr Fialko
6637d39531SVolodymyr Fialko static __rte_always_inline uint64_t
leftover_get(uint64_t slab,uint32_t shift,uint64_t mask)6737d39531SVolodymyr Fialko leftover_get(uint64_t slab, uint32_t shift, uint64_t mask)
6837d39531SVolodymyr Fialko {
6937d39531SVolodymyr Fialko return (slab & mask) << shift;
7037d39531SVolodymyr Fialko }
7137d39531SVolodymyr Fialko
7237d39531SVolodymyr Fialko void
pdcp_cnt_report_fill(struct pdcp_cnt_bitmap bitmap,struct entity_state state,uint8_t * data,uint16_t data_len)7337d39531SVolodymyr Fialko pdcp_cnt_report_fill(struct pdcp_cnt_bitmap bitmap, struct entity_state state,
7437d39531SVolodymyr Fialko uint8_t *data, uint16_t data_len)
7537d39531SVolodymyr Fialko {
7637d39531SVolodymyr Fialko uint64_t slab = 0, next_slab = 0, leftover;
7737d39531SVolodymyr Fialko uint32_t zeros, report_len, diff;
7837d39531SVolodymyr Fialko uint32_t slab_id, next_slab_id;
7937d39531SVolodymyr Fialko uint32_t pos = 0, next_pos = 0;
8037d39531SVolodymyr Fialko
8137d39531SVolodymyr Fialko const uint32_t start_count = state.rx_deliv + 1;
8237d39531SVolodymyr Fialko const uint32_t nb_slabs = bitmap.size / RTE_BITMAP_SLAB_BIT_SIZE;
8337d39531SVolodymyr Fialko const uint32_t nb_data_slabs = data_len / SLAB_BYTE_SIZE;
8437d39531SVolodymyr Fialko const uint32_t start_slab_id = start_count / RTE_BITMAP_SLAB_BIT_SIZE;
8537d39531SVolodymyr Fialko const uint32_t stop_slab_id = (start_slab_id + nb_data_slabs) % nb_slabs;
8637d39531SVolodymyr Fialko const uint32_t shift = start_count % RTE_BITMAP_SLAB_BIT_SIZE;
8737d39531SVolodymyr Fialko const uint32_t leftover_shift = shift ? RTE_BITMAP_SLAB_BIT_SIZE - shift : 0;
8837d39531SVolodymyr Fialko const uint8_t *data_end = RTE_PTR_ADD(data, data_len + SLAB_BYTE_SIZE);
8937d39531SVolodymyr Fialko
9037d39531SVolodymyr Fialko /* NOTE: Mask required to workaround case - when shift is not needed */
9137d39531SVolodymyr Fialko const uint64_t leftover_mask = shift ? ~0 : 0;
9237d39531SVolodymyr Fialko
9337d39531SVolodymyr Fialko /* NOTE: implement scan init at to set custom position */
9437d39531SVolodymyr Fialko __rte_bitmap_scan_init(bitmap.bmp);
9537d39531SVolodymyr Fialko while (true) {
9637d39531SVolodymyr Fialko assert(rte_bitmap_scan(bitmap.bmp, &pos, &slab) == 1);
9737d39531SVolodymyr Fialko slab_id = pos / RTE_BITMAP_SLAB_BIT_SIZE;
9837d39531SVolodymyr Fialko if (slab_id >= start_slab_id)
9937d39531SVolodymyr Fialko break;
10037d39531SVolodymyr Fialko }
10137d39531SVolodymyr Fialko
10237d39531SVolodymyr Fialko report_len = nb_data_slabs;
10337d39531SVolodymyr Fialko
10437d39531SVolodymyr Fialko if (slab_id > start_slab_id) {
10537d39531SVolodymyr Fialko /* Zero slabs at beginning */
10637d39531SVolodymyr Fialko zeros = (slab_id - start_slab_id - 1) * SLAB_BYTE_SIZE;
10737d39531SVolodymyr Fialko memset(data, 0, zeros);
10837d39531SVolodymyr Fialko data = RTE_PTR_ADD(data, zeros);
10937d39531SVolodymyr Fialko leftover = leftover_get(slab, leftover_shift, leftover_mask);
11037d39531SVolodymyr Fialko memcpy(data, &leftover, SLAB_BYTE_SIZE);
11137d39531SVolodymyr Fialko data = RTE_PTR_ADD(data, SLAB_BYTE_SIZE);
11237d39531SVolodymyr Fialko report_len -= (slab_id - start_slab_id);
11337d39531SVolodymyr Fialko }
11437d39531SVolodymyr Fialko
11537d39531SVolodymyr Fialko while (report_len) {
11637d39531SVolodymyr Fialko rte_bitmap_scan(bitmap.bmp, &next_pos, &next_slab);
11737d39531SVolodymyr Fialko next_slab_id = next_pos / RTE_BITMAP_SLAB_BIT_SIZE;
11837d39531SVolodymyr Fialko diff = (next_slab_id + nb_slabs - slab_id) % nb_slabs;
11937d39531SVolodymyr Fialko
12037d39531SVolodymyr Fialko /* If next_slab_id == slab_id - overlap */
12137d39531SVolodymyr Fialko diff += !(next_slab_id ^ slab_id) * nb_slabs;
12237d39531SVolodymyr Fialko
12337d39531SVolodymyr Fialko /* Size check - next slab is outsize of size range */
12437d39531SVolodymyr Fialko if (diff > report_len) {
12537d39531SVolodymyr Fialko next_slab = 0;
12637d39531SVolodymyr Fialko next_slab_id = stop_slab_id;
12737d39531SVolodymyr Fialko diff = report_len;
12837d39531SVolodymyr Fialko }
12937d39531SVolodymyr Fialko
13037d39531SVolodymyr Fialko report_len -= diff;
13137d39531SVolodymyr Fialko
13237d39531SVolodymyr Fialko /* Calculate gap between slabs, taking wrap around into account */
13337d39531SVolodymyr Fialko zeros = (next_slab_id + nb_slabs - slab_id - 1) % nb_slabs;
13437d39531SVolodymyr Fialko if (zeros) {
13537d39531SVolodymyr Fialko /* Non continues slabs, align them individually */
13637d39531SVolodymyr Fialko slab >>= shift;
13737d39531SVolodymyr Fialko memcpy(data, &slab, SLAB_BYTE_SIZE);
13837d39531SVolodymyr Fialko data = RTE_PTR_ADD(data, SLAB_BYTE_SIZE);
13937d39531SVolodymyr Fialko
14037d39531SVolodymyr Fialko /* Fill zeros between slabs */
14137d39531SVolodymyr Fialko zeros = (zeros - 1) * SLAB_BYTE_SIZE;
14237d39531SVolodymyr Fialko memset(data, 0, zeros);
14337d39531SVolodymyr Fialko data = RTE_PTR_ADD(data, zeros);
14437d39531SVolodymyr Fialko
14537d39531SVolodymyr Fialko /* Align beginning of next slab */
14637d39531SVolodymyr Fialko leftover = leftover_get(next_slab, leftover_shift, leftover_mask);
14737d39531SVolodymyr Fialko memcpy(data, &leftover, SLAB_BYTE_SIZE);
14837d39531SVolodymyr Fialko data = RTE_PTR_ADD(data, SLAB_BYTE_SIZE);
14937d39531SVolodymyr Fialko } else {
15037d39531SVolodymyr Fialko /* Continues slabs, combine them */
15137d39531SVolodymyr Fialko uint64_t new_slab = (slab >> shift) |
15237d39531SVolodymyr Fialko leftover_get(next_slab, leftover_shift, leftover_mask);
15337d39531SVolodymyr Fialko memcpy(data, &new_slab, SLAB_BYTE_SIZE);
15437d39531SVolodymyr Fialko data = RTE_PTR_ADD(data, SLAB_BYTE_SIZE);
15537d39531SVolodymyr Fialko }
15637d39531SVolodymyr Fialko
15737d39531SVolodymyr Fialko slab = next_slab;
15837d39531SVolodymyr Fialko pos = next_pos;
15937d39531SVolodymyr Fialko slab_id = next_slab_id;
16037d39531SVolodymyr Fialko
16137d39531SVolodymyr Fialko };
16237d39531SVolodymyr Fialko
16337d39531SVolodymyr Fialko assert(data < data_end);
16437d39531SVolodymyr Fialko }
165