1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(C) 2023 Marvell.
3 */
4
5 #include <rte_bitmap.h>
6 #include <rte_pdcp.h>
7
8 #include "pdcp_cnt.h"
9 #include "pdcp_ctrl_pdu.h"
10 #include "pdcp_entity.h"
11
12 #define SLAB_BYTE_SIZE (RTE_BITMAP_SLAB_BIT_SIZE / 8)
13
14 uint32_t
pdcp_cnt_bitmap_get_memory_footprint(const struct rte_pdcp_entity_conf * conf)15 pdcp_cnt_bitmap_get_memory_footprint(const struct rte_pdcp_entity_conf *conf)
16 {
17 uint32_t n_bits = pdcp_window_size_get(conf->pdcp_xfrm.sn_size);
18
19 return rte_bitmap_get_memory_footprint(n_bits);
20 }
21
22 int
pdcp_cnt_bitmap_create(struct entity_priv_dl_part * dl,uint32_t nb_elem,void * bitmap_mem,uint32_t mem_size)23 pdcp_cnt_bitmap_create(struct entity_priv_dl_part *dl, uint32_t nb_elem,
24 void *bitmap_mem, uint32_t mem_size)
25 {
26 dl->bitmap.bmp = rte_bitmap_init(nb_elem, bitmap_mem, mem_size);
27 if (dl->bitmap.bmp == NULL)
28 return -EINVAL;
29
30 dl->bitmap.size = nb_elem;
31
32 return 0;
33 }
34
35 void
pdcp_cnt_bitmap_set(struct pdcp_cnt_bitmap bitmap,uint32_t count)36 pdcp_cnt_bitmap_set(struct pdcp_cnt_bitmap bitmap, uint32_t count)
37 {
38 rte_bitmap_set(bitmap.bmp, count % bitmap.size);
39 }
40
41 bool
pdcp_cnt_bitmap_is_set(struct pdcp_cnt_bitmap bitmap,uint32_t count)42 pdcp_cnt_bitmap_is_set(struct pdcp_cnt_bitmap bitmap, uint32_t count)
43 {
44 return rte_bitmap_get(bitmap.bmp, count % bitmap.size);
45 }
46
47 void
pdcp_cnt_bitmap_range_clear(struct pdcp_cnt_bitmap bitmap,uint32_t start,uint32_t stop)48 pdcp_cnt_bitmap_range_clear(struct pdcp_cnt_bitmap bitmap, uint32_t start, uint32_t stop)
49 {
50 uint32_t i;
51
52 for (i = start; i < stop; i++)
53 rte_bitmap_clear(bitmap.bmp, i % bitmap.size);
54 }
55
56 uint16_t
pdcp_cnt_get_bitmap_size(uint32_t pending_bytes)57 pdcp_cnt_get_bitmap_size(uint32_t pending_bytes)
58 {
59 /*
60 * Round up bitmap size to slab size to operate only on slabs sizes, instead of individual
61 * bytes
62 */
63 return RTE_ALIGN_MUL_CEIL(pending_bytes, SLAB_BYTE_SIZE);
64 }
65
66 static __rte_always_inline uint64_t
leftover_get(uint64_t slab,uint32_t shift,uint64_t mask)67 leftover_get(uint64_t slab, uint32_t shift, uint64_t mask)
68 {
69 return (slab & mask) << shift;
70 }
71
72 void
pdcp_cnt_report_fill(struct pdcp_cnt_bitmap bitmap,struct entity_state state,uint8_t * data,uint16_t data_len)73 pdcp_cnt_report_fill(struct pdcp_cnt_bitmap bitmap, struct entity_state state,
74 uint8_t *data, uint16_t data_len)
75 {
76 uint64_t slab = 0, next_slab = 0, leftover;
77 uint32_t zeros, report_len, diff;
78 uint32_t slab_id, next_slab_id;
79 uint32_t pos = 0, next_pos = 0;
80
81 const uint32_t start_count = state.rx_deliv + 1;
82 const uint32_t nb_slabs = bitmap.size / RTE_BITMAP_SLAB_BIT_SIZE;
83 const uint32_t nb_data_slabs = data_len / SLAB_BYTE_SIZE;
84 const uint32_t start_slab_id = start_count / RTE_BITMAP_SLAB_BIT_SIZE;
85 const uint32_t stop_slab_id = (start_slab_id + nb_data_slabs) % nb_slabs;
86 const uint32_t shift = start_count % RTE_BITMAP_SLAB_BIT_SIZE;
87 const uint32_t leftover_shift = shift ? RTE_BITMAP_SLAB_BIT_SIZE - shift : 0;
88 const uint8_t *data_end = RTE_PTR_ADD(data, data_len + SLAB_BYTE_SIZE);
89
90 /* NOTE: Mask required to workaround case - when shift is not needed */
91 const uint64_t leftover_mask = shift ? ~0 : 0;
92
93 /* NOTE: implement scan init at to set custom position */
94 __rte_bitmap_scan_init(bitmap.bmp);
95 while (true) {
96 assert(rte_bitmap_scan(bitmap.bmp, &pos, &slab) == 1);
97 slab_id = pos / RTE_BITMAP_SLAB_BIT_SIZE;
98 if (slab_id >= start_slab_id)
99 break;
100 }
101
102 report_len = nb_data_slabs;
103
104 if (slab_id > start_slab_id) {
105 /* Zero slabs at beginning */
106 zeros = (slab_id - start_slab_id - 1) * SLAB_BYTE_SIZE;
107 memset(data, 0, zeros);
108 data = RTE_PTR_ADD(data, zeros);
109 leftover = leftover_get(slab, leftover_shift, leftover_mask);
110 memcpy(data, &leftover, SLAB_BYTE_SIZE);
111 data = RTE_PTR_ADD(data, SLAB_BYTE_SIZE);
112 report_len -= (slab_id - start_slab_id);
113 }
114
115 while (report_len) {
116 rte_bitmap_scan(bitmap.bmp, &next_pos, &next_slab);
117 next_slab_id = next_pos / RTE_BITMAP_SLAB_BIT_SIZE;
118 diff = (next_slab_id + nb_slabs - slab_id) % nb_slabs;
119
120 /* If next_slab_id == slab_id - overlap */
121 diff += !(next_slab_id ^ slab_id) * nb_slabs;
122
123 /* Size check - next slab is outsize of size range */
124 if (diff > report_len) {
125 next_slab = 0;
126 next_slab_id = stop_slab_id;
127 diff = report_len;
128 }
129
130 report_len -= diff;
131
132 /* Calculate gap between slabs, taking wrap around into account */
133 zeros = (next_slab_id + nb_slabs - slab_id - 1) % nb_slabs;
134 if (zeros) {
135 /* Non continues slabs, align them individually */
136 slab >>= shift;
137 memcpy(data, &slab, SLAB_BYTE_SIZE);
138 data = RTE_PTR_ADD(data, SLAB_BYTE_SIZE);
139
140 /* Fill zeros between slabs */
141 zeros = (zeros - 1) * SLAB_BYTE_SIZE;
142 memset(data, 0, zeros);
143 data = RTE_PTR_ADD(data, zeros);
144
145 /* Align beginning of next slab */
146 leftover = leftover_get(next_slab, leftover_shift, leftover_mask);
147 memcpy(data, &leftover, SLAB_BYTE_SIZE);
148 data = RTE_PTR_ADD(data, SLAB_BYTE_SIZE);
149 } else {
150 /* Continues slabs, combine them */
151 uint64_t new_slab = (slab >> shift) |
152 leftover_get(next_slab, leftover_shift, leftover_mask);
153 memcpy(data, &new_slab, SLAB_BYTE_SIZE);
154 data = RTE_PTR_ADD(data, SLAB_BYTE_SIZE);
155 }
156
157 slab = next_slab;
158 pos = next_pos;
159 slab_id = next_slab_id;
160
161 };
162
163 assert(data < data_end);
164 }
165