xref: /dpdk/drivers/net/bnxt/hcapi/cfa/hcapi_cfa_p4.c (revision 1993b267dbcb66555c4bb54db15fc2fc69ef902d)
17100b0e5SJeffrey Huang /* SPDX-License-Identifier: BSD-3-Clause
27100b0e5SJeffrey Huang  * Copyright(c) 2019-2021 Broadcom
37100b0e5SJeffrey Huang  * All rights reserved.
47100b0e5SJeffrey Huang  */
508e1af1aSFarah Smith 
67100b0e5SJeffrey Huang #include <stdint.h>
77100b0e5SJeffrey Huang #include <stdlib.h>
87100b0e5SJeffrey Huang #include <stdbool.h>
97100b0e5SJeffrey Huang #include <string.h>
107100b0e5SJeffrey Huang #include "lookup3.h"
117100b0e5SJeffrey Huang #include "rand.h"
127100b0e5SJeffrey Huang 
1308e1af1aSFarah Smith #include "hcapi_cfa.h"
147100b0e5SJeffrey Huang #include "hcapi_cfa_defs.h"
157100b0e5SJeffrey Huang 
16b56a8975SPeter Spreadborough static uint32_t hcapi_cfa_lkup_lkup3_init_cfg;
17b56a8975SPeter Spreadborough static uint32_t hcapi_cfa_lkup_em_seed_mem[HCAPI_CFA_LKUP_SEED_MEM_SIZE];
18b56a8975SPeter Spreadborough static bool hcapi_cfa_lkup_init;
197100b0e5SJeffrey Huang 
SWAP_WORDS32(uint32_t val32)207100b0e5SJeffrey Huang static inline uint32_t SWAP_WORDS32(uint32_t val32)
217100b0e5SJeffrey Huang {
2208e1af1aSFarah Smith 	return (((val32 & 0x0000ffff) << 16) | ((val32 & 0xffff0000) >> 16));
237100b0e5SJeffrey Huang }
247100b0e5SJeffrey Huang 
hcapi_cfa_seeds_init(void)257100b0e5SJeffrey Huang static void hcapi_cfa_seeds_init(void)
267100b0e5SJeffrey Huang {
277100b0e5SJeffrey Huang 	int i;
287100b0e5SJeffrey Huang 	uint32_t r;
297100b0e5SJeffrey Huang 
307100b0e5SJeffrey Huang 	if (hcapi_cfa_lkup_init)
317100b0e5SJeffrey Huang 		return;
327100b0e5SJeffrey Huang 
337100b0e5SJeffrey Huang 	hcapi_cfa_lkup_init = true;
347100b0e5SJeffrey Huang 
357100b0e5SJeffrey Huang 	/* Initialize the lfsr */
367100b0e5SJeffrey Huang 	rand_init();
377100b0e5SJeffrey Huang 
387100b0e5SJeffrey Huang 	/* RX and TX use the same seed values */
397100b0e5SJeffrey Huang 	hcapi_cfa_lkup_lkup3_init_cfg = SWAP_WORDS32(rand32());
407100b0e5SJeffrey Huang 
417100b0e5SJeffrey Huang 	for (i = 0; i < HCAPI_CFA_LKUP_SEED_MEM_SIZE / 2; i++) {
427100b0e5SJeffrey Huang 		r = SWAP_WORDS32(rand32());
437100b0e5SJeffrey Huang 		hcapi_cfa_lkup_em_seed_mem[i * 2] = r;
447100b0e5SJeffrey Huang 		r = SWAP_WORDS32(rand32());
457100b0e5SJeffrey Huang 		hcapi_cfa_lkup_em_seed_mem[i * 2 + 1] = (r & 0x1);
467100b0e5SJeffrey Huang 	}
477100b0e5SJeffrey Huang }
487100b0e5SJeffrey Huang 
hcapi_cfa_crc32_hash(uint8_t * key)497100b0e5SJeffrey Huang static uint32_t hcapi_cfa_crc32_hash(uint8_t *key)
507100b0e5SJeffrey Huang {
517100b0e5SJeffrey Huang 	int i;
527100b0e5SJeffrey Huang 	uint32_t index;
537100b0e5SJeffrey Huang 	uint32_t val1, val2;
547100b0e5SJeffrey Huang 	uint8_t temp[4];
557100b0e5SJeffrey Huang 	uint8_t *kptr = key;
567100b0e5SJeffrey Huang 
577100b0e5SJeffrey Huang 	/* Do byte-wise XOR of the 52-byte HASH key first. */
587100b0e5SJeffrey Huang 	index = *key;
597100b0e5SJeffrey Huang 	kptr--;
607100b0e5SJeffrey Huang 
617100b0e5SJeffrey Huang 	for (i = CFA_P4_EEM_KEY_MAX_SIZE - 2; i >= 0; i--) {
627100b0e5SJeffrey Huang 		index = index ^ *kptr;
637100b0e5SJeffrey Huang 		kptr--;
647100b0e5SJeffrey Huang 	}
657100b0e5SJeffrey Huang 
667100b0e5SJeffrey Huang 	/* Get seeds */
677100b0e5SJeffrey Huang 	val1 = hcapi_cfa_lkup_em_seed_mem[index * 2];
687100b0e5SJeffrey Huang 	val2 = hcapi_cfa_lkup_em_seed_mem[index * 2 + 1];
697100b0e5SJeffrey Huang 
707100b0e5SJeffrey Huang 	temp[3] = (uint8_t)(val1 >> 24);
717100b0e5SJeffrey Huang 	temp[2] = (uint8_t)(val1 >> 16);
727100b0e5SJeffrey Huang 	temp[1] = (uint8_t)(val1 >> 8);
737100b0e5SJeffrey Huang 	temp[0] = (uint8_t)(val1 & 0xff);
747100b0e5SJeffrey Huang 	val1 = 0;
757100b0e5SJeffrey Huang 
767100b0e5SJeffrey Huang 	/* Start with seed */
777100b0e5SJeffrey Huang 	if (!(val2 & 0x1))
787100b0e5SJeffrey Huang 		val1 = hcapi_cfa_crc32i(~val1, temp, 4);
797100b0e5SJeffrey Huang 
8008e1af1aSFarah Smith 	val1 = hcapi_cfa_crc32i(~val1, (key - (CFA_P4_EEM_KEY_MAX_SIZE - 1)),
817100b0e5SJeffrey Huang 				CFA_P4_EEM_KEY_MAX_SIZE);
827100b0e5SJeffrey Huang 
837100b0e5SJeffrey Huang 	/* End with seed */
847100b0e5SJeffrey Huang 	if (val2 & 0x1)
857100b0e5SJeffrey Huang 		val1 = hcapi_cfa_crc32i(~val1, temp, 4);
867100b0e5SJeffrey Huang 
877100b0e5SJeffrey Huang 	return val1;
887100b0e5SJeffrey Huang }
897100b0e5SJeffrey Huang 
hcapi_cfa_lookup3_hash(uint8_t * in_key)907100b0e5SJeffrey Huang static uint32_t hcapi_cfa_lookup3_hash(uint8_t *in_key)
917100b0e5SJeffrey Huang {
927100b0e5SJeffrey Huang 	uint32_t val1;
937100b0e5SJeffrey Huang 
9408e1af1aSFarah Smith 	val1 = hashword(((uint32_t *)in_key) + 1,
957100b0e5SJeffrey Huang 			CFA_P4_EEM_KEY_MAX_SIZE / (sizeof(uint32_t)),
967100b0e5SJeffrey Huang 			hcapi_cfa_lkup_lkup3_init_cfg);
977100b0e5SJeffrey Huang 
987100b0e5SJeffrey Huang 	return val1;
997100b0e5SJeffrey Huang }
1007100b0e5SJeffrey Huang 
hcapi_get_table_page(struct hcapi_cfa_em_table * mem,uint32_t page)10108e1af1aSFarah Smith uint64_t hcapi_get_table_page(struct hcapi_cfa_em_table *mem, uint32_t page)
1027100b0e5SJeffrey Huang {
1037100b0e5SJeffrey Huang 	int level = 0;
1047100b0e5SJeffrey Huang 	uint64_t addr;
1057100b0e5SJeffrey Huang 
1067100b0e5SJeffrey Huang 	if (mem == NULL)
1077100b0e5SJeffrey Huang 		return 0;
1087100b0e5SJeffrey Huang 
1097100b0e5SJeffrey Huang 	/*
1107100b0e5SJeffrey Huang 	 * Use the level according to the num_level of page table
1117100b0e5SJeffrey Huang 	 */
1127100b0e5SJeffrey Huang 	level = mem->num_lvl - 1;
1137100b0e5SJeffrey Huang 
11408e1af1aSFarah Smith 	addr = (uint64_t)mem->pg_tbl[level].pg_va_tbl[page];
1157100b0e5SJeffrey Huang 
1167100b0e5SJeffrey Huang 	return addr;
1177100b0e5SJeffrey Huang }
1187100b0e5SJeffrey Huang 
1197100b0e5SJeffrey Huang /** Approximation of HCAPI hcapi_cfa_key_hash()
1207100b0e5SJeffrey Huang  *
1217100b0e5SJeffrey Huang  * Return:
1227100b0e5SJeffrey Huang  *
1237100b0e5SJeffrey Huang  */
hcapi_cfa_p4_key_hash(uint64_t * key_data,uint16_t bitlen)124b56a8975SPeter Spreadborough uint64_t hcapi_cfa_p4_key_hash(uint64_t *key_data,
1257100b0e5SJeffrey Huang 			       uint16_t bitlen)
1267100b0e5SJeffrey Huang {
1277100b0e5SJeffrey Huang 	uint32_t key0_hash;
1287100b0e5SJeffrey Huang 	uint32_t key1_hash;
1297100b0e5SJeffrey Huang 
1307100b0e5SJeffrey Huang 	/*
1317100b0e5SJeffrey Huang 	 * Init the seeds if needed
1327100b0e5SJeffrey Huang 	 */
1337100b0e5SJeffrey Huang 	if (!hcapi_cfa_lkup_init)
1347100b0e5SJeffrey Huang 		hcapi_cfa_seeds_init();
1357100b0e5SJeffrey Huang 
13608e1af1aSFarah Smith 	key0_hash =
13708e1af1aSFarah Smith 		hcapi_cfa_crc32_hash(((uint8_t *)key_data) + (bitlen / 8) - 1);
1387100b0e5SJeffrey Huang 
1397100b0e5SJeffrey Huang 	key1_hash = hcapi_cfa_lookup3_hash((uint8_t *)key_data);
1407100b0e5SJeffrey Huang 
1417100b0e5SJeffrey Huang 	return ((uint64_t)key0_hash) << 32 | (uint64_t)key1_hash;
1427100b0e5SJeffrey Huang }
1437100b0e5SJeffrey Huang 
hcapi_cfa_p4_key_hw_op_put(struct hcapi_cfa_hwop * op,struct hcapi_cfa_key_data * key_obj)14408e1af1aSFarah Smith static int hcapi_cfa_p4_key_hw_op_put(struct hcapi_cfa_hwop *op,
1457100b0e5SJeffrey Huang 				      struct hcapi_cfa_key_data *key_obj)
1467100b0e5SJeffrey Huang {
1477100b0e5SJeffrey Huang 	int rc = 0;
1487100b0e5SJeffrey Huang 
14908e1af1aSFarah Smith 	memcpy((uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
15008e1af1aSFarah Smith 	       key_obj->data, key_obj->size);
1517100b0e5SJeffrey Huang 
1527100b0e5SJeffrey Huang 	return rc;
1537100b0e5SJeffrey Huang }
1547100b0e5SJeffrey Huang 
hcapi_cfa_p4_key_hw_op_get(struct hcapi_cfa_hwop * op,struct hcapi_cfa_key_data * key_obj)15508e1af1aSFarah Smith static int hcapi_cfa_p4_key_hw_op_get(struct hcapi_cfa_hwop *op,
1567100b0e5SJeffrey Huang 				      struct hcapi_cfa_key_data *key_obj)
1577100b0e5SJeffrey Huang {
1587100b0e5SJeffrey Huang 	int rc = 0;
1597100b0e5SJeffrey Huang 
1607100b0e5SJeffrey Huang 	memcpy(key_obj->data,
16108e1af1aSFarah Smith 	       (uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
1627100b0e5SJeffrey Huang 	       key_obj->size);
1637100b0e5SJeffrey Huang 
1647100b0e5SJeffrey Huang 	return rc;
1657100b0e5SJeffrey Huang }
1667100b0e5SJeffrey Huang 
hcapi_cfa_p4_key_hw_op_add(struct hcapi_cfa_hwop * op,struct hcapi_cfa_key_data * key_obj)16708e1af1aSFarah Smith static int hcapi_cfa_p4_key_hw_op_add(struct hcapi_cfa_hwop *op,
1687100b0e5SJeffrey Huang 				      struct hcapi_cfa_key_data *key_obj)
1697100b0e5SJeffrey Huang {
1707100b0e5SJeffrey Huang 	int rc = 0;
1717100b0e5SJeffrey Huang 	struct cfa_p4_eem_64b_entry table_entry;
1727100b0e5SJeffrey Huang 
1737100b0e5SJeffrey Huang 	/*
1747100b0e5SJeffrey Huang 	 * Is entry free?
1757100b0e5SJeffrey Huang 	 */
1767100b0e5SJeffrey Huang 	memcpy(&table_entry,
17708e1af1aSFarah Smith 	       (uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
1787100b0e5SJeffrey Huang 	       key_obj->size);
1797100b0e5SJeffrey Huang 
1807100b0e5SJeffrey Huang 	/*
1817100b0e5SJeffrey Huang 	 * If this is entry is valid then report failure
1827100b0e5SJeffrey Huang 	 */
1837100b0e5SJeffrey Huang 	if (table_entry.hdr.word1 & (1 << CFA_P4_EEM_ENTRY_VALID_SHIFT))
1847100b0e5SJeffrey Huang 		return -1;
1857100b0e5SJeffrey Huang 
18608e1af1aSFarah Smith 	memcpy((uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
18708e1af1aSFarah Smith 	       key_obj->data, key_obj->size);
1887100b0e5SJeffrey Huang 
1897100b0e5SJeffrey Huang 	return rc;
1907100b0e5SJeffrey Huang }
1917100b0e5SJeffrey Huang 
hcapi_cfa_p4_key_hw_op_del(struct hcapi_cfa_hwop * op,struct hcapi_cfa_key_data * key_obj)19208e1af1aSFarah Smith static int hcapi_cfa_p4_key_hw_op_del(struct hcapi_cfa_hwop *op,
1937100b0e5SJeffrey Huang 				      struct hcapi_cfa_key_data *key_obj)
1947100b0e5SJeffrey Huang {
1957100b0e5SJeffrey Huang 	int rc = 0;
1967100b0e5SJeffrey Huang 	struct cfa_p4_eem_64b_entry table_entry;
1977100b0e5SJeffrey Huang 
1987100b0e5SJeffrey Huang 	/*
1997100b0e5SJeffrey Huang 	 * Read entry
2007100b0e5SJeffrey Huang 	 */
2017100b0e5SJeffrey Huang 	memcpy(&table_entry,
20208e1af1aSFarah Smith 	       (uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset,
2037100b0e5SJeffrey Huang 	       key_obj->size);
2047100b0e5SJeffrey Huang 
2057100b0e5SJeffrey Huang 	/*
2067100b0e5SJeffrey Huang 	 * If this is not a valid entry then report failure.
2077100b0e5SJeffrey Huang 	 */
2087100b0e5SJeffrey Huang 	if (table_entry.hdr.word1 & (1 << CFA_P4_EEM_ENTRY_VALID_SHIFT)) {
2097100b0e5SJeffrey Huang 		/*
2107100b0e5SJeffrey Huang 		 * If a key has been provided then verify the key matches
2117100b0e5SJeffrey Huang 		 * before deleting the entry.
2127100b0e5SJeffrey Huang 		 */
2137100b0e5SJeffrey Huang 		if (key_obj->data != NULL) {
21408e1af1aSFarah Smith 			if (memcmp(&table_entry, key_obj->data,
2157100b0e5SJeffrey Huang 				   key_obj->size) != 0)
2167100b0e5SJeffrey Huang 				return -1;
2177100b0e5SJeffrey Huang 		}
2187100b0e5SJeffrey Huang 	} else {
2197100b0e5SJeffrey Huang 		return -1;
2207100b0e5SJeffrey Huang 	}
2217100b0e5SJeffrey Huang 
2227100b0e5SJeffrey Huang 	/*
2237100b0e5SJeffrey Huang 	 * Delete entry
2247100b0e5SJeffrey Huang 	 */
22508e1af1aSFarah Smith 	memset((uint8_t *)(uintptr_t)op->hw.base_addr + key_obj->offset, 0, key_obj->size);
2267100b0e5SJeffrey Huang 
2277100b0e5SJeffrey Huang 	return rc;
2287100b0e5SJeffrey Huang }
2297100b0e5SJeffrey Huang 
230*1993b267SShahaji Bhosle /** Approximation of hcapi_cfa_key_hw_op()
2317100b0e5SJeffrey Huang  *
2327100b0e5SJeffrey Huang  *
2337100b0e5SJeffrey Huang  */
hcapi_cfa_p4_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)23408e1af1aSFarah Smith static int hcapi_cfa_p4_key_hw_op(struct hcapi_cfa_hwop *op,
2357100b0e5SJeffrey Huang 				  struct hcapi_cfa_key_tbl *key_tbl,
2367100b0e5SJeffrey Huang 				  struct hcapi_cfa_key_data *key_obj,
2377100b0e5SJeffrey Huang 				  struct hcapi_cfa_key_loc *key_loc)
2387100b0e5SJeffrey Huang {
2397100b0e5SJeffrey Huang 	int rc = 0;
24008e1af1aSFarah Smith 	struct hcapi_cfa_em_table *em_tbl;
24108e1af1aSFarah Smith 	uint32_t page;
2427100b0e5SJeffrey Huang 
24308e1af1aSFarah Smith 	if (op == NULL || key_tbl == NULL || key_obj == NULL || key_loc == NULL)
2447100b0e5SJeffrey Huang 		return -1;
2457100b0e5SJeffrey Huang 
24608e1af1aSFarah Smith 	page = key_obj->offset / key_tbl->page_size;
24708e1af1aSFarah Smith 	em_tbl = (struct hcapi_cfa_em_table *)key_tbl->base0;
24808e1af1aSFarah Smith 	op->hw.base_addr = hcapi_get_table_page(em_tbl, page);
2497100b0e5SJeffrey Huang 	/* Offset is adjusted to be the offset into the page */
2507100b0e5SJeffrey Huang 	key_obj->offset = key_obj->offset % key_tbl->page_size;
2517100b0e5SJeffrey Huang 
2527100b0e5SJeffrey Huang 	if (op->hw.base_addr == 0)
2537100b0e5SJeffrey Huang 		return -1;
2547100b0e5SJeffrey Huang 
2557100b0e5SJeffrey Huang 	switch (op->opcode) {
2567100b0e5SJeffrey Huang 	case HCAPI_CFA_HWOPS_PUT: /**< Write to HW operation */
25708e1af1aSFarah Smith 		rc = hcapi_cfa_p4_key_hw_op_put(op, key_obj);
2587100b0e5SJeffrey Huang 		break;
2597100b0e5SJeffrey Huang 	case HCAPI_CFA_HWOPS_GET: /**< Read from HW operation */
26008e1af1aSFarah Smith 		rc = hcapi_cfa_p4_key_hw_op_get(op, key_obj);
2617100b0e5SJeffrey Huang 		break;
2627100b0e5SJeffrey Huang 	case HCAPI_CFA_HWOPS_ADD:
26308e1af1aSFarah Smith 		/**< For operations which require more then simple
26408e1af1aSFarah Smith 		 * writes to HW, this operation is used.  The
2657100b0e5SJeffrey Huang 		 * distinction with this operation when compared
2667100b0e5SJeffrey Huang 		 * to the PUT ops is that this operation is used
2677100b0e5SJeffrey Huang 		 * in conjunction with the HCAPI_CFA_HWOPS_DEL
2687100b0e5SJeffrey Huang 		 * op to remove the operations issued by the
2697100b0e5SJeffrey Huang 		 * ADD OP.
2707100b0e5SJeffrey Huang 		 */
2717100b0e5SJeffrey Huang 
27208e1af1aSFarah Smith 		rc = hcapi_cfa_p4_key_hw_op_add(op, key_obj);
2737100b0e5SJeffrey Huang 
2747100b0e5SJeffrey Huang 		break;
2757100b0e5SJeffrey Huang 	case HCAPI_CFA_HWOPS_DEL:
27608e1af1aSFarah Smith 		rc = hcapi_cfa_p4_key_hw_op_del(op, key_obj);
2777100b0e5SJeffrey Huang 		break;
2787100b0e5SJeffrey Huang 	default:
2797100b0e5SJeffrey Huang 		rc = -1;
2807100b0e5SJeffrey Huang 		break;
2817100b0e5SJeffrey Huang 	}
2827100b0e5SJeffrey Huang 
2837100b0e5SJeffrey Huang 	return rc;
2847100b0e5SJeffrey Huang }
28508e1af1aSFarah Smith 
28608e1af1aSFarah Smith const struct hcapi_cfa_devops cfa_p4_devops = {
28708e1af1aSFarah Smith 	.hcapi_cfa_key_hash = hcapi_cfa_p4_key_hash,
28808e1af1aSFarah Smith 	.hcapi_cfa_key_hw_op = hcapi_cfa_p4_key_hw_op,
28908e1af1aSFarah Smith };
290