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