1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2019-2020 Broadcom
3 * All rights reserved.
4 */
5 #include <inttypes.h>
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_defs.h"
14
15 #define HCAPI_CFA_LKUP_SEED_MEM_SIZE 512
16 uint32_t hcapi_cfa_lkup_lkup3_init_cfg;
17 uint32_t hcapi_cfa_lkup_em_seed_mem[HCAPI_CFA_LKUP_SEED_MEM_SIZE];
18 bool hcapi_cfa_lkup_init;
19
SWAP_WORDS32(uint32_t val32)20 static inline uint32_t SWAP_WORDS32(uint32_t val32)
21 {
22 return (((val32 & 0x0000ffff) << 16) |
23 ((val32 & 0xffff0000) >> 16));
24 }
25
hcapi_cfa_seeds_init(void)26 static void hcapi_cfa_seeds_init(void)
27 {
28 int i;
29 uint32_t r;
30
31 if (hcapi_cfa_lkup_init)
32 return;
33
34 hcapi_cfa_lkup_init = true;
35
36 /* Initialize the lfsr */
37 rand_init();
38
39 /* RX and TX use the same seed values */
40 hcapi_cfa_lkup_lkup3_init_cfg = SWAP_WORDS32(rand32());
41
42 for (i = 0; i < HCAPI_CFA_LKUP_SEED_MEM_SIZE / 2; i++) {
43 r = SWAP_WORDS32(rand32());
44 hcapi_cfa_lkup_em_seed_mem[i * 2] = r;
45 r = SWAP_WORDS32(rand32());
46 hcapi_cfa_lkup_em_seed_mem[i * 2 + 1] = (r & 0x1);
47 }
48 }
49
50 /* CRC32i support for Key0 hash */
51 #define ucrc32(ch, crc) (crc32tbl[((crc) ^ (ch)) & 0xff] ^ ((crc) >> 8))
52 #define crc32(x, y) crc32i(~0, x, y)
53
54 static const uint32_t crc32tbl[] = { /* CRC polynomial 0xedb88320 */
55 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba,
56 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
57 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
58 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
59 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
60 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
61 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec,
62 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
63 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
64 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
65 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940,
66 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
67 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116,
68 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
69 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
70 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
71 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a,
72 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
73 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818,
74 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
75 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
76 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
77 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c,
78 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
79 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
80 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
81 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
82 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
83 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086,
84 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
85 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4,
86 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
87 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
88 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
89 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
90 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
91 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe,
92 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
93 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
94 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
95 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252,
96 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
97 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60,
98 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
99 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
100 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
101 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04,
102 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
103 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a,
104 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
105 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
106 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
107 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e,
108 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
109 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
110 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
111 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
112 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
113 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0,
114 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
115 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6,
116 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
117 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
118 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
119 };
120
hcapi_cfa_crc32i(uint32_t crc,const uint8_t * buf,size_t len)121 static uint32_t hcapi_cfa_crc32i(uint32_t crc, const uint8_t *buf, size_t len)
122 {
123 int l;
124
125 #ifdef TF_EEM_DEBUG
126 TFP_DRV_LOG(DEBUG, "CRC2:");
127 #endif
128 for (l = (len - 1); l >= 0; l--) {
129 crc = ucrc32(buf[l], crc);
130 #ifdef TF_EEM_DEBUG
131 TFP_DRV_LOG(DEBUG,
132 "%02X %08X %08X\n",
133 (buf[l] & 0xff),
134 crc,
135 ~crc);
136 #endif
137 }
138
139 #ifdef TF_EEM_DEBUG
140 TFP_DRV_LOG(DEBUG, "\n");
141 #endif
142
143 return ~crc;
144 }
145
hcapi_cfa_crc32_hash(uint8_t * key)146 static uint32_t hcapi_cfa_crc32_hash(uint8_t *key)
147 {
148 int i;
149 uint32_t index;
150 uint32_t val1, val2;
151 uint8_t temp[4];
152 uint8_t *kptr = key;
153
154 /* Do byte-wise XOR of the 52-byte HASH key first. */
155 index = *key;
156 kptr--;
157
158 for (i = CFA_P4_EEM_KEY_MAX_SIZE - 2; i >= 0; i--) {
159 index = index ^ *kptr;
160 kptr--;
161 }
162
163 /* Get seeds */
164 val1 = hcapi_cfa_lkup_em_seed_mem[index * 2];
165 val2 = hcapi_cfa_lkup_em_seed_mem[index * 2 + 1];
166
167 temp[3] = (uint8_t)(val1 >> 24);
168 temp[2] = (uint8_t)(val1 >> 16);
169 temp[1] = (uint8_t)(val1 >> 8);
170 temp[0] = (uint8_t)(val1 & 0xff);
171 val1 = 0;
172
173 /* Start with seed */
174 if (!(val2 & 0x1))
175 val1 = hcapi_cfa_crc32i(~val1, temp, 4);
176
177 val1 = hcapi_cfa_crc32i(~val1,
178 (key - (CFA_P4_EEM_KEY_MAX_SIZE - 1)),
179 CFA_P4_EEM_KEY_MAX_SIZE);
180
181 /* End with seed */
182 if (val2 & 0x1)
183 val1 = hcapi_cfa_crc32i(~val1, temp, 4);
184
185 return val1;
186 }
187
hcapi_cfa_lookup3_hash(uint8_t * in_key)188 static uint32_t hcapi_cfa_lookup3_hash(uint8_t *in_key)
189 {
190 uint32_t val1;
191
192 val1 = hashword(((const uint32_t *)(uintptr_t *)in_key) + 1,
193 CFA_P4_EEM_KEY_MAX_SIZE / (sizeof(uint32_t)),
194 hcapi_cfa_lkup_lkup3_init_cfg);
195
196 return val1;
197 }
198
199
hcapi_get_table_page(struct hcapi_cfa_em_table * mem,uint32_t page)200 uint64_t hcapi_get_table_page(struct hcapi_cfa_em_table *mem,
201 uint32_t page)
202 {
203 int level = 0;
204 uint64_t addr;
205
206 if (mem == NULL)
207 return 0;
208
209 /*
210 * Use the level according to the num_level of page table
211 */
212 level = mem->num_lvl - 1;
213
214 addr = (uintptr_t)mem->pg_tbl[level].pg_va_tbl[page];
215
216 return addr;
217 }
218
219 /** Approximation of HCAPI hcapi_cfa_key_hash()
220 *
221 * Return:
222 *
223 */
hcapi_cfa_key_hash(uint64_t * key_data,uint16_t bitlen)224 uint64_t hcapi_cfa_key_hash(uint64_t *key_data,
225 uint16_t bitlen)
226 {
227 uint32_t key0_hash;
228 uint32_t key1_hash;
229
230 /*
231 * Init the seeds if needed
232 */
233 if (!hcapi_cfa_lkup_init)
234 hcapi_cfa_seeds_init();
235
236 key0_hash = hcapi_cfa_crc32_hash(((uint8_t *)key_data) +
237 (bitlen / 8) - 1);
238
239 key1_hash = hcapi_cfa_lookup3_hash((uint8_t *)key_data);
240
241 return ((uint64_t)key0_hash) << 32 | (uint64_t)key1_hash;
242 }
243
hcapi_cfa_key_hw_op_put(struct hcapi_cfa_hwop * op,struct hcapi_cfa_key_data * key_obj)244 static int hcapi_cfa_key_hw_op_put(struct hcapi_cfa_hwop *op,
245 struct hcapi_cfa_key_data *key_obj)
246 {
247 int rc = 0;
248
249 memcpy((uint8_t *)(uintptr_t)op->hw.base_addr +
250 key_obj->offset,
251 key_obj->data,
252 key_obj->size);
253
254 return rc;
255 }
256
hcapi_cfa_key_hw_op_get(struct hcapi_cfa_hwop * op,struct hcapi_cfa_key_data * key_obj)257 static int hcapi_cfa_key_hw_op_get(struct hcapi_cfa_hwop *op,
258 struct hcapi_cfa_key_data *key_obj)
259 {
260 int rc = 0;
261
262 memcpy(key_obj->data,
263 (uint8_t *)(uintptr_t)op->hw.base_addr +
264 key_obj->offset,
265 key_obj->size);
266
267 return rc;
268 }
269
hcapi_cfa_key_hw_op_add(struct hcapi_cfa_hwop * op,struct hcapi_cfa_key_data * key_obj)270 static int hcapi_cfa_key_hw_op_add(struct hcapi_cfa_hwop *op,
271 struct hcapi_cfa_key_data *key_obj)
272 {
273 int rc = 0;
274 struct cfa_p4_eem_64b_entry table_entry;
275
276 /*
277 * Is entry free?
278 */
279 memcpy(&table_entry,
280 (uint8_t *)(uintptr_t)op->hw.base_addr +
281 key_obj->offset,
282 key_obj->size);
283
284 /*
285 * If this is entry is valid then report failure
286 */
287 if (table_entry.hdr.word1 & (1 << CFA_P4_EEM_ENTRY_VALID_SHIFT))
288 return -1;
289
290 memcpy((uint8_t *)(uintptr_t)op->hw.base_addr +
291 key_obj->offset,
292 key_obj->data,
293 key_obj->size);
294
295 return rc;
296 }
297
hcapi_cfa_key_hw_op_del(struct hcapi_cfa_hwop * op,struct hcapi_cfa_key_data * key_obj)298 static int hcapi_cfa_key_hw_op_del(struct hcapi_cfa_hwop *op,
299 struct hcapi_cfa_key_data *key_obj)
300 {
301 int rc = 0;
302 struct cfa_p4_eem_64b_entry table_entry;
303
304 /*
305 * Read entry
306 */
307 memcpy(&table_entry,
308 (uint8_t *)(uintptr_t)op->hw.base_addr +
309 key_obj->offset,
310 key_obj->size);
311
312 /*
313 * If this is not a valid entry then report failure.
314 */
315 if (table_entry.hdr.word1 & (1 << CFA_P4_EEM_ENTRY_VALID_SHIFT)) {
316 /*
317 * If a key has been provided then verify the key matches
318 * before deleting the entry.
319 */
320 if (key_obj->data != NULL) {
321 if (memcmp(&table_entry,
322 key_obj->data,
323 key_obj->size) != 0)
324 return -1;
325 }
326 } else {
327 return -1;
328 }
329
330
331 /*
332 * Delete entry
333 */
334 memset((uint8_t *)(uintptr_t)op->hw.base_addr +
335 key_obj->offset,
336 0,
337 key_obj->size);
338
339 return rc;
340 }
341
342
343 /** Apporiximation of hcapi_cfa_key_hw_op()
344 *
345 *
346 */
hcapi_cfa_key_hw_op(struct hcapi_cfa_hwop * op,struct hcapi_cfa_key_tbl * key_tbl,struct hcapi_cfa_key_data * key_obj,struct hcapi_cfa_key_loc * key_loc)347 int hcapi_cfa_key_hw_op(struct hcapi_cfa_hwop *op,
348 struct hcapi_cfa_key_tbl *key_tbl,
349 struct hcapi_cfa_key_data *key_obj,
350 struct hcapi_cfa_key_loc *key_loc)
351 {
352 int rc = 0;
353
354 if (op == NULL ||
355 key_tbl == NULL ||
356 key_obj == NULL ||
357 key_loc == NULL)
358 return -1;
359
360 op->hw.base_addr =
361 hcapi_get_table_page((struct hcapi_cfa_em_table *)
362 key_tbl->base0,
363 key_obj->offset / key_tbl->page_size);
364 /* Offset is adjusted to be the offset into the page */
365 key_obj->offset = key_obj->offset % key_tbl->page_size;
366
367 if (op->hw.base_addr == 0)
368 return -1;
369
370 switch (op->opcode) {
371 case HCAPI_CFA_HWOPS_PUT: /**< Write to HW operation */
372 rc = hcapi_cfa_key_hw_op_put(op, key_obj);
373 break;
374 case HCAPI_CFA_HWOPS_GET: /**< Read from HW operation */
375 rc = hcapi_cfa_key_hw_op_get(op, key_obj);
376 break;
377 case HCAPI_CFA_HWOPS_ADD:
378 /**< For operations which require more than
379 * simple writes to HW, this operation is used. The
380 * distinction with this operation when compared
381 * to the PUT ops is that this operation is used
382 * in conjunction with the HCAPI_CFA_HWOPS_DEL
383 * op to remove the operations issued by the
384 * ADD OP.
385 */
386
387 rc = hcapi_cfa_key_hw_op_add(op, key_obj);
388
389 break;
390 case HCAPI_CFA_HWOPS_DEL:
391 rc = hcapi_cfa_key_hw_op_del(op, key_obj);
392 break;
393 default:
394 rc = -1;
395 break;
396 }
397
398 return rc;
399 }
400