Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2019-2021 Broadcom
3 : : * All rights reserved.
4 : : */
5 : :
6 : : #include <stdint.h>
7 : : #include <stdlib.h>
8 : : #include <stdbool.h>
9 : : #include <string.h>
10 : : #include "lookup3.h"
11 : : #include "rand.h"
12 : :
13 : : #include "hcapi_cfa.h"
14 : : #include "hcapi_cfa_defs.h"
15 : :
16 : : static uint32_t hcapi_cfa_lkup_lkup3_init_cfg;
17 : : static uint32_t hcapi_cfa_lkup_em_seed_mem[HCAPI_CFA_LKUP_SEED_MEM_SIZE];
18 : : static bool hcapi_cfa_lkup_init;
19 : :
20 : : static inline uint32_t SWAP_WORDS32(uint32_t val32)
21 : : {
22 : 0 : return (((val32 & 0x0000ffff) << 16) | ((val32 & 0xffff0000) >> 16));
23 : : }
24 : :
25 : 0 : static void hcapi_cfa_seeds_init(void)
26 : : {
27 : : int i;
28 : : uint32_t r;
29 : :
30 [ # # ]: 0 : if (hcapi_cfa_lkup_init)
31 : : return;
32 : :
33 : 0 : hcapi_cfa_lkup_init = true;
34 : :
35 : : /* Initialize the lfsr */
36 : 0 : rand_init();
37 : :
38 : : /* RX and TX use the same seed values */
39 : 0 : hcapi_cfa_lkup_lkup3_init_cfg = SWAP_WORDS32(rand32());
40 : :
41 [ # # ]: 0 : for (i = 0; i < HCAPI_CFA_LKUP_SEED_MEM_SIZE / 2; i++) {
42 : 0 : r = SWAP_WORDS32(rand32());
43 : 0 : hcapi_cfa_lkup_em_seed_mem[i * 2] = r;
44 : 0 : r = SWAP_WORDS32(rand32());
45 : 0 : hcapi_cfa_lkup_em_seed_mem[i * 2 + 1] = (r & 0x1);
46 : : }
47 : : }
48 : :
49 : 0 : static uint32_t hcapi_cfa_crc32_hash(uint8_t *key)
50 : : {
51 : : int i;
52 : : uint32_t index;
53 : : uint32_t val1, val2;
54 : : uint8_t temp[4];
55 : : uint8_t *kptr = key;
56 : :
57 : : /* Do byte-wise XOR of the 52-byte HASH key first. */
58 : 0 : index = *key;
59 : 0 : kptr--;
60 : :
61 [ # # ]: 0 : for (i = CFA_P4_EEM_KEY_MAX_SIZE - 2; i >= 0; i--) {
62 : 0 : index = index ^ *kptr;
63 : 0 : kptr--;
64 : : }
65 : :
66 : : /* Get seeds */
67 : 0 : val1 = hcapi_cfa_lkup_em_seed_mem[index * 2];
68 : 0 : val2 = hcapi_cfa_lkup_em_seed_mem[index * 2 + 1];
69 : :
70 : 0 : temp[3] = (uint8_t)(val1 >> 24);
71 : 0 : temp[2] = (uint8_t)(val1 >> 16);
72 : 0 : temp[1] = (uint8_t)(val1 >> 8);
73 : 0 : temp[0] = (uint8_t)(val1 & 0xff);
74 : : val1 = 0;
75 : :
76 : : /* Start with seed */
77 [ # # ]: 0 : if (!(val2 & 0x1))
78 : 0 : val1 = hcapi_cfa_crc32i(~val1, temp, 4);
79 : :
80 : 0 : val1 = hcapi_cfa_crc32i(~val1, (key - (CFA_P4_EEM_KEY_MAX_SIZE - 1)),
81 : : CFA_P4_EEM_KEY_MAX_SIZE);
82 : :
83 : : /* End with seed */
84 [ # # ]: 0 : if (val2 & 0x1)
85 : 0 : val1 = hcapi_cfa_crc32i(~val1, temp, 4);
86 : :
87 : 0 : return val1;
88 : : }
89 : :
90 : : static uint32_t hcapi_cfa_lookup3_hash(uint8_t *in_key)
91 : : {
92 : : uint32_t val1;
93 : :
94 : 0 : val1 = hashword(((uint32_t *)in_key) + 1,
95 : : CFA_P4_EEM_KEY_MAX_SIZE / (sizeof(uint32_t)),
96 : : hcapi_cfa_lkup_lkup3_init_cfg);
97 : :
98 : : return val1;
99 : : }
100 : :
101 : 0 : uint64_t hcapi_get_table_page(struct hcapi_cfa_em_table *mem, uint32_t page)
102 : : {
103 : : int level = 0;
104 : : uint64_t addr;
105 : :
106 [ # # ]: 0 : if (mem == NULL)
107 : : return 0;
108 : :
109 : : /*
110 : : * Use the level according to the num_level of page table
111 : : */
112 : 0 : level = mem->num_lvl - 1;
113 : :
114 : 0 : addr = (uint64_t)mem->pg_tbl[level].pg_va_tbl[page];
115 : :
116 : 0 : return addr;
117 : : }
118 : :
119 : : /** Approximation of HCAPI hcapi_cfa_key_hash()
120 : : *
121 : : * Return:
122 : : *
123 : : */
124 : 0 : uint64_t hcapi_cfa_p4_key_hash(uint64_t *key_data,
125 : : uint16_t bitlen)
126 : : {
127 : : uint32_t key0_hash;
128 : : uint32_t key1_hash;
129 : :
130 : : /*
131 : : * Init the seeds if needed
132 : : */
133 [ # # ]: 0 : if (!hcapi_cfa_lkup_init)
134 : 0 : hcapi_cfa_seeds_init();
135 : :
136 : : key0_hash =
137 : 0 : hcapi_cfa_crc32_hash(((uint8_t *)key_data) + (bitlen / 8) - 1);
138 : :
139 : : key1_hash = hcapi_cfa_lookup3_hash((uint8_t *)key_data);
140 : :
141 : 0 : return ((uint64_t)key0_hash) << 32 | (uint64_t)key1_hash;
142 : : }
143 : :
144 : : static int hcapi_cfa_p4_key_hw_op_put(struct hcapi_cfa_hwop *op,
145 : : struct hcapi_cfa_key_data *key_obj)
146 : : {
147 : : int rc = 0;
148 : :
149 : 0 : memcpy((uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
150 : 0 : key_obj->data, key_obj->size);
151 : :
152 : : return rc;
153 : : }
154 : :
155 : : static int hcapi_cfa_p4_key_hw_op_get(struct hcapi_cfa_hwop *op,
156 : : struct hcapi_cfa_key_data *key_obj)
157 : : {
158 : : int rc = 0;
159 : :
160 : 0 : memcpy(key_obj->data,
161 : 0 : (uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
162 : 0 : key_obj->size);
163 : :
164 : : return rc;
165 : : }
166 : :
167 : 0 : static int hcapi_cfa_p4_key_hw_op_add(struct hcapi_cfa_hwop *op,
168 : : struct hcapi_cfa_key_data *key_obj)
169 : : {
170 : : int rc = 0;
171 : : struct cfa_p4_eem_64b_entry table_entry;
172 : :
173 : : /*
174 : : * Is entry free?
175 : : */
176 : 0 : memcpy(&table_entry,
177 : 0 : (uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
178 [ # # ]: 0 : key_obj->size);
179 : :
180 : : /*
181 : : * If this is entry is valid then report failure
182 : : */
183 [ # # ]: 0 : if (table_entry.hdr.word1 & (1 << CFA_P4_EEM_ENTRY_VALID_SHIFT))
184 : : return -1;
185 : :
186 : : memcpy((uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
187 : 0 : key_obj->data, key_obj->size);
188 : :
189 : 0 : return rc;
190 : : }
191 : :
192 : 0 : static int hcapi_cfa_p4_key_hw_op_del(struct hcapi_cfa_hwop *op,
193 : : struct hcapi_cfa_key_data *key_obj)
194 : : {
195 : : int rc = 0;
196 : : struct cfa_p4_eem_64b_entry table_entry;
197 : :
198 : : /*
199 : : * Read entry
200 : : */
201 : 0 : memcpy(&table_entry,
202 : 0 : (uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
203 [ # # ]: 0 : key_obj->size);
204 : :
205 : : /*
206 : : * If this is not a valid entry then report failure.
207 : : */
208 [ # # ]: 0 : if (table_entry.hdr.word1 & (1 << CFA_P4_EEM_ENTRY_VALID_SHIFT)) {
209 : : /*
210 : : * If a key has been provided then verify the key matches
211 : : * before deleting the entry.
212 : : */
213 [ # # ]: 0 : if (key_obj->data != NULL) {
214 [ # # ]: 0 : if (memcmp(&table_entry, key_obj->data,
215 : : key_obj->size) != 0)
216 : : return -1;
217 : : }
218 : : } else {
219 : : return -1;
220 : : }
221 : :
222 : : /*
223 : : * Delete entry
224 : : */
225 : : memset((uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset, 0, key_obj->size);
226 : :
227 : 0 : return rc;
228 : : }
229 : :
230 : : /** Approximation of hcapi_cfa_key_hw_op()
231 : : *
232 : : *
233 : : */
234 : 0 : static int hcapi_cfa_p4_key_hw_op(struct hcapi_cfa_hwop *op,
235 : : struct hcapi_cfa_key_tbl *key_tbl,
236 : : struct hcapi_cfa_key_data *key_obj,
237 : : struct hcapi_cfa_key_loc *key_loc)
238 : : {
239 : : int rc = 0;
240 : : struct hcapi_cfa_em_table *em_tbl;
241 : : uint32_t page;
242 : :
243 [ # # # # ]: 0 : if (op == NULL || key_tbl == NULL || key_obj == NULL || key_loc == NULL)
244 : : return -1;
245 : :
246 : 0 : page = key_obj->offset / key_tbl->page_size;
247 : 0 : em_tbl = (struct hcapi_cfa_em_table *)key_tbl->base0;
248 : 0 : op->hw.base_addr = hcapi_get_table_page(em_tbl, page);
249 : : /* Offset is adjusted to be the offset into the page */
250 : 0 : key_obj->offset = key_obj->offset % key_tbl->page_size;
251 : :
252 [ # # ]: 0 : if (op->hw.base_addr == 0)
253 : : return -1;
254 : :
255 [ # # # # : 0 : switch (op->opcode) {
# ]
256 : : case HCAPI_CFA_HWOPS_PUT: /**< Write to HW operation */
257 : : rc = hcapi_cfa_p4_key_hw_op_put(op, key_obj);
258 : 0 : break;
259 : : case HCAPI_CFA_HWOPS_GET: /**< Read from HW operation */
260 : : rc = hcapi_cfa_p4_key_hw_op_get(op, key_obj);
261 : 0 : break;
262 : 0 : case HCAPI_CFA_HWOPS_ADD:
263 : : /**< For operations which require more then simple
264 : : * writes to HW, this operation is used. The
265 : : * distinction with this operation when compared
266 : : * to the PUT ops is that this operation is used
267 : : * in conjunction with the HCAPI_CFA_HWOPS_DEL
268 : : * op to remove the operations issued by the
269 : : * ADD OP.
270 : : */
271 : :
272 : 0 : rc = hcapi_cfa_p4_key_hw_op_add(op, key_obj);
273 : :
274 : 0 : break;
275 : 0 : case HCAPI_CFA_HWOPS_DEL:
276 : 0 : rc = hcapi_cfa_p4_key_hw_op_del(op, key_obj);
277 : 0 : break;
278 : : default:
279 : : rc = -1;
280 : : break;
281 : : }
282 : :
283 : : return rc;
284 : : }
285 : :
286 : : const struct hcapi_cfa_devops cfa_p4_devops = {
287 : : .hcapi_cfa_key_hash = hcapi_cfa_p4_key_hash,
288 : : .hcapi_cfa_key_hw_op = hcapi_cfa_p4_key_hw_op,
289 : : };
|