[v1,28/50] net/ntnic: add categorizer (CAT) FPGA module

Message ID 20241006203728.330792-29-sil-plv@napatech.com (mailing list archive)
State Superseded
Delegated to: Ferruh Yigit
Headers
Series Provide: flow filter init API, Enable virtual queues, fix ntnic issues for release 24.07 |

Checks

Context Check Description
ci/checkpatch warning coding style issues

Commit Message

Serhii Iliushyk Oct. 6, 2024, 8:36 p.m. UTC
From: Oleksandr Kolomeiets <okl-plv@napatech.com>

The Categorizer module’s main purpose is to is select the behavior
of other modules in the FPGA pipeline depending on a protocol check.

Signed-off-by: Oleksandr Kolomeiets <okl-plv@napatech.com>
---
 drivers/net/ntnic/include/hw_mod_backend.h    | 205 ++++
 drivers/net/ntnic/meson.build                 |   1 +
 drivers/net/ntnic/nthw/flow_api/flow_api.c    |  15 +
 .../nthw/flow_api/hw_mod/hw_mod_backend.c     | 109 +-
 .../ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c   | 985 ++++++++++++++++++
 .../supported/nthw_fpga_9563_055_049_0000.c   | 264 ++++-
 6 files changed, 1577 insertions(+), 2 deletions(-)
 create mode 100644 drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c
  

Patch

diff --git a/drivers/net/ntnic/include/hw_mod_backend.h b/drivers/net/ntnic/include/hw_mod_backend.h
index f47153cbb6..20b10faf5e 100644
--- a/drivers/net/ntnic/include/hw_mod_backend.h
+++ b/drivers/net/ntnic/include/hw_mod_backend.h
@@ -22,12 +22,116 @@ 
 
 #define MAX_PHYS_ADAPTERS 8
 
+#define VER_MAJOR(ver) (((ver) >> 16) & 0xffff)
+#define VER_MINOR(ver) ((ver) & 0xffff)
+
+struct flow_api_backend_s;
+struct common_func_s;
+
+void *callocate_mod(struct common_func_s *mod, int sets, ...);
+void zero_module_cache(struct common_func_s *mod);
+
+#define ALL_ENTRIES -1000
+
+#define INDEX_TOO_LARGE (NT_LOG(INF, FILTER, "ERROR:%s: Index too large\n", __func__), -2)
+
+#define WORD_OFF_TOO_LARGE (NT_LOG(INF, FILTER, "ERROR:%s: Word offset too large\n", __func__), -3)
+
+#define UNSUP_FIELD                                                                               \
+	(NT_LOG(INF, FILTER, "ERROR:%s: Unsupported field in NIC module\n", __func__), -5)
+
+#define UNSUP_VER                                                                                 \
+	(NT_LOG(INF, FILTER, "ERROR:%s: Unsupported NIC module: %s ver %i.%i\n", __func__, _MOD_, \
+		VER_MAJOR(_VER_), VER_MINOR(_VER_)),                                              \
+	 -4)
+
+#define COUNT_ERROR(_RESOURCE_)                                                                   \
+	(NT_LOG(INF, FILTER,                                                                      \
+		"ERROR:%s: Insufficient resource [ %s ] : NIC module: %s ver %i.%i\n", __func__,  \
+		#_RESOURCE_, _MOD_, VER_MAJOR(_VER_), VER_MINOR(_VER_)),                          \
+	 -4)
+
+#define NOT_FOUND 0xffffffff
+
+enum {
+	EXTRA_INDEXES
+};
+
+#define GET(cached_val, val) ({ *(val) = *(cached_val); })
+
+#define SET(cached_val, val) ({ *(cached_val) = *(val); })
+
+#define GET_SET(cached_val, val)                                                                  \
+	do {                                                                                      \
+		uint32_t *temp_val = (val);                                                       \
+		typeof(cached_val) *temp_cached_val = &(cached_val);                          \
+		if (get)                                                                          \
+			GET(temp_cached_val, temp_val);                                           \
+		else                                                                              \
+			SET(temp_cached_val, temp_val);                                           \
+	} while (0)
+
+#define GET_SIGNED(cached_val, val) ({ *(val) = (uint32_t)(*(cached_val)); })
+
+#define SET_SIGNED(cached_val, val) ({ *(cached_val) = (int32_t)(*(val)); })
+
+#define GET_SET_SIGNED(cached_val, val)                                                           \
+	do {                                                                                      \
+		uint32_t *temp_val = (val);                                                       \
+		typeof(cached_val) *temp_cached_val = &(cached_val);                          \
+		if (get)                                                                          \
+			GET_SIGNED(temp_cached_val, temp_val);                                    \
+		else                                                                              \
+			SET_SIGNED(temp_cached_val, temp_val);                                    \
+	} while (0)
+
+#define FIND_EQUAL_INDEX(be_module_reg, type, idx, start, nb_elements)                            \
+	do {                                                                                      \
+		typeof(be_module_reg) *temp_be_module =                                       \
+			(typeof(be_module_reg) *)be_module_reg;                               \
+		typeof(idx) tmp_idx = (idx);                                                  \
+		typeof(nb_elements) tmp_nb_elements = (nb_elements);                          \
+		unsigned int start_idx = (unsigned int)(start);                                   \
+		*value = NOT_FOUND;                                                               \
+		for (unsigned int i = start_idx; i < tmp_nb_elements; i++) {                      \
+			if ((unsigned int)(tmp_idx) == i)                                         \
+				continue;                                                         \
+			if (memcmp(&temp_be_module[tmp_idx], &temp_be_module[i], sizeof(type)) == \
+			    0) {                                                                  \
+				*value = i;                                                       \
+				break;                                                            \
+			}                                                                         \
+		}                                                                                 \
+	} while (0)
+
+#define DO_COMPARE_INDEXS(be_module_reg, type, idx, cmp_idx)                                      \
+	do {                                                                                      \
+		typeof(be_module_reg) *temp_be_module = &(be_module_reg);                     \
+		typeof(idx) tmp_idx = (idx);                                                  \
+		typeof(cmp_idx) tmp_cmp_idx = (cmp_idx);                                      \
+		if ((unsigned int)(tmp_idx) != (unsigned int)(tmp_cmp_idx)) {                     \
+			(void)memcmp(temp_be_module + tmp_idx, &temp_be_module[tmp_cmp_idx],      \
+				     sizeof(type));                                               \
+		}                                                                                 \
+	} while (0)
+
+enum km_flm_if_select_e {
+	KM_FLM_IF_FIRST = 0,
+	KM_FLM_IF_SECOND = 1
+};
+
+#define FIELD_START_INDEX 100
+
 #define COMMON_FUNC_INFO_S                                                                        \
 	int ver;                                                                                  \
 	void *base;                                                                               \
 	unsigned int alloced_size;                                                                \
 	int debug
 
+struct common_func_s {
+	COMMON_FUNC_INFO_S;
+};
+
 struct cat_func_s {
 	COMMON_FUNC_INFO_S;
 	uint32_t nb_cat_funcs;
@@ -48,6 +152,104 @@  struct cat_func_s {
 		struct hw_mod_cat_v21_s v21;
 	};
 };
+enum hw_cat_e {
+	/*
+	 * functions initial CAT v18
+	 */
+	/* 00 */ HW_CAT_CFN_SET_ALL_DEFAULTS = 0,
+	/* 01 */ HW_CAT_CFN_PRESET_ALL,
+	/* 02 */ HW_CAT_CFN_COMPARE,
+	/* 03 */ HW_CAT_CFN_FIND,
+	/* 04 */ HW_CAT_CFN_COPY_FROM,
+	/* 05 */ HW_CAT_COT_PRESET_ALL,
+	/* 06 */ HW_CAT_COT_COMPARE,
+	/* 07 */ HW_CAT_COT_FIND,
+	/* 08 */ HW_CAT_COT_COPY_FROM,
+	/* fields */
+	/* 00 */ HW_CAT_CFN_ENABLE = FIELD_START_INDEX,
+	/* 01 */ HW_CAT_CFN_INV,
+	/* 02 */ HW_CAT_CFN_PTC_INV,
+	/* 03 */ HW_CAT_CFN_PTC_ISL,
+	/* 04 */ HW_CAT_CFN_PTC_CFP,
+	/* 05 */ HW_CAT_CFN_PTC_MAC,
+	/* 06 */ HW_CAT_CFN_PTC_L2,
+	/* 07 */ HW_CAT_CFN_PTC_VNTAG,
+	/* 08 */ HW_CAT_CFN_PTC_VLAN,
+	/* 09 */ HW_CAT_CFN_PTC_MPLS,
+	/* 10 */ HW_CAT_CFN_PTC_L3,
+	/* 11 */ HW_CAT_CFN_PTC_FRAG,
+	/* 12 */ HW_CAT_CFN_PTC_IP_PROT,
+	/* 13 */ HW_CAT_CFN_PTC_L4,
+	/* 14 */ HW_CAT_CFN_PTC_TUNNEL,
+	/* 15 */ HW_CAT_CFN_PTC_TNL_L2,
+	/* 16 */ HW_CAT_CFN_PTC_TNL_VLAN,
+	/* 17 */ HW_CAT_CFN_PTC_TNL_MPLS,
+	/* 18 */ HW_CAT_CFN_PTC_TNL_L3,
+	/* 19 */ HW_CAT_CFN_PTC_TNL_FRAG,
+	/* 20 */ HW_CAT_CFN_PTC_TNL_IP_PROT,
+	/* 21 */ HW_CAT_CFN_PTC_TNL_L4,
+	/* 22 */ HW_CAT_CFN_ERR_INV,
+	/* 23 */ HW_CAT_CFN_ERR_CV,
+	/* 24 */ HW_CAT_CFN_ERR_FCS,
+	/* 25 */ HW_CAT_CFN_ERR_TRUNC,
+	/* 26 */ HW_CAT_CFN_ERR_L3_CS,
+	/* 27 */ HW_CAT_CFN_ERR_L4_CS,
+	/* 28 */ HW_CAT_CFN_MAC_PORT,
+	/* 29 */ HW_CAT_CFN_PM_CMP,
+	/* 30 */ HW_CAT_CFN_PM_DCT,
+	/* 31 */ HW_CAT_CFN_PM_EXT_INV,
+	/* 32 */ HW_CAT_CFN_PM_CMB,
+	/* 33 */ HW_CAT_CFN_PM_AND_INV,
+	/* 34 */ HW_CAT_CFN_PM_OR_INV,
+	/* 35 */ HW_CAT_CFN_PM_INV,
+	/* 36 */ HW_CAT_CFN_LC,
+	/* 37 */ HW_CAT_CFN_LC_INV,
+	/* 38 */ HW_CAT_CFN_KM0_OR,
+	/* 39 */ HW_CAT_CFN_KM1_OR,
+	/* 40 */ HW_CAT_KCE_ENABLE_BM,
+	/* 41 */ HW_CAT_KCS_CATEGORY,
+	/* 42 */ HW_CAT_FTE_ENABLE_BM,
+	/* 43 */ HW_CAT_CTE_ENABLE_BM,
+	/* 44 */ HW_CAT_CTS_CAT_A,
+	/* 45 */ HW_CAT_CTS_CAT_B,
+	/* 46 */ HW_CAT_COT_COLOR,
+	/* 47 */ HW_CAT_COT_KM,
+	/* 48 */ HW_CAT_CCT_COLOR,
+	/* 49 */ HW_CAT_CCT_KM,
+	/* 50 */ HW_CAT_KCC_KEY,
+	/* 51 */ HW_CAT_KCC_CATEGORY,
+	/* 52 */ HW_CAT_KCC_ID,
+	/* 53 */ HW_CAT_EXO_DYN,
+	/* 54 */ HW_CAT_EXO_OFS,
+	/* 55 */ HW_CAT_RCK_DATA,
+	/* 56 */ HW_CAT_LEN_LOWER,
+	/* 57 */ HW_CAT_LEN_UPPER,
+	/* 58 */ HW_CAT_LEN_DYN1,
+	/* 59 */ HW_CAT_LEN_DYN2,
+	/* 60 */ HW_CAT_LEN_INV,
+	/* 61 */ HW_CAT_CFN_ERR_TNL_L3_CS,
+	/* 62 */ HW_CAT_CFN_ERR_TNL_L4_CS,
+	/* 63 */ HW_CAT_CFN_ERR_TTL_EXP,
+	/* 64 */ HW_CAT_CFN_ERR_TNL_TTL_EXP,
+};
+
+bool hw_mod_cat_present(struct flow_api_backend_s *be);
+int hw_mod_cat_alloc(struct flow_api_backend_s *be);
+void hw_mod_cat_free(struct flow_api_backend_s *be);
+int hw_mod_cat_reset(struct flow_api_backend_s *be);
+int hw_mod_cat_cfn_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_cfn_set(struct flow_api_backend_s *be, enum hw_cat_e field, int index, int word_off,
+	uint32_t value);
+
+int hw_mod_cat_cte_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_cts_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_cot_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_cct_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_kcc_flush(struct flow_api_backend_s *be, int start_idx, int count);
+
+int hw_mod_cat_exo_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_rck_flush(struct flow_api_backend_s *be, int start_idx, int count);
+int hw_mod_cat_len_flush(struct flow_api_backend_s *be, int start_idx, int count);
 
 struct km_func_s {
 	COMMON_FUNC_INFO_S;
@@ -279,6 +481,9 @@  struct flow_api_backend_s {
 	void *be_dev;
 	const struct flow_api_backend_ops *iface;
 
+	/* flow filter FPGA modules */
+	struct cat_func_s cat;
+
 	/* NIC attributes */
 	unsigned int num_phy_ports;
 	unsigned int num_rx_ports;
diff --git a/drivers/net/ntnic/meson.build b/drivers/net/ntnic/meson.build
index 57d1ded2a7..3d394f9bad 100644
--- a/drivers/net/ntnic/meson.build
+++ b/drivers/net/ntnic/meson.build
@@ -49,6 +49,7 @@  sources = files(
         'nthw/flow_api/flow_kcc.c',
         'nthw/flow_api/flow_km.c',
         'nthw/flow_api/hw_mod/hw_mod_backend.c',
+        'nthw/flow_api/hw_mod/hw_mod_cat.c',
         'nthw/flow_filter/flow_nthw_cat.c',
         'nthw/flow_filter/flow_nthw_csu.c',
         'nthw/flow_filter/flow_nthw_flm.c',
diff --git a/drivers/net/ntnic/nthw/flow_api/flow_api.c b/drivers/net/ntnic/nthw/flow_api/flow_api.c
index 4bab8983c9..3b1d7c5850 100644
--- a/drivers/net/ntnic/nthw/flow_api/flow_api.c
+++ b/drivers/net/ntnic/nthw/flow_api/flow_api.c
@@ -272,12 +272,27 @@  struct flow_nic_dev *flow_api_create(uint8_t adapter_no, const struct flow_api_b
 	if (init_resource_elements(ndev, RES_QUEUE, ndev->be.max_queues))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_CAT_CFN, ndev->be.cat.nb_cat_funcs))
+		goto err_exit;
+
 	if (init_resource_elements(ndev, RES_CAT_COT, ndev->be.max_categories))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_CAT_EXO, ndev->be.cat.nb_pm_ext))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_CAT_LEN, ndev->be.cat.nb_len))
+		goto err_exit;
+
+	if (init_resource_elements(ndev, RES_KM_FLOW_TYPE, ndev->be.cat.nb_flow_types))
+		goto err_exit;
+
 	if (init_resource_elements(ndev, RES_SLC_LR_RCP, ndev->be.max_categories))
 		goto err_exit;
 
+	if (init_resource_elements(ndev, RES_FLM_FLOW_TYPE, ndev->be.cat.nb_flow_types))
+		goto err_exit;
+
 	/* may need IPF, COR */
 
 	/* check all defined has been initialized */
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
index 5966dc6e8c..33fb4df126 100644
--- a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_backend.c
@@ -5,6 +5,79 @@ 
 
 #include "hw_mod_backend.h"
 
+#include <stdlib.h>
+#include <string.h>
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+
+static const struct {
+	const char *name;
+	int (*allocate)(struct flow_api_backend_s *be);
+	void (*free)(struct flow_api_backend_s *be);
+	int (*reset)(struct flow_api_backend_s *be);
+	bool (*present)(struct flow_api_backend_s *be);
+} module[] = {
+	{ "CAT", hw_mod_cat_alloc, hw_mod_cat_free, hw_mod_cat_reset, hw_mod_cat_present },
+};
+#define MOD_COUNT (ARRAY_SIZE(module))
+
+void *callocate_mod(struct common_func_s *mod, int sets, ...)
+{
+#define MAX_SETS 38
+	void *base = NULL;
+	void **plist[MAX_SETS];
+	int len[MAX_SETS];
+	int offs[MAX_SETS];
+	unsigned int total_bytes = 0;
+	int cnt, elem_size;
+
+	assert(sets <= MAX_SETS);
+	assert(sets > 0);
+
+	va_list args;
+	va_start(args, sets);
+
+	for (int i = 0; i < sets; i++) {
+		plist[i] = va_arg(args, void *);
+		cnt = va_arg(args, int);
+		elem_size = va_arg(args, int);
+		offs[i] = EXTRA_INDEXES * elem_size;
+		len[i] = offs[i] + cnt * elem_size;
+		total_bytes += len[i];
+	}
+
+	if (total_bytes > 0) {
+		base = calloc(1, total_bytes);
+
+		if (base) {
+			char *p_b = (char *)base;
+
+			for (int i = 0; i < sets; i++) {
+				*plist[i] = (void *)((char *)p_b + offs[i]);
+				p_b += len[i];
+			}
+
+		} else {
+			NT_LOG(ERR, FILTER, "ERROR: module memory allocation failed\n");
+		}
+
+	} else {
+		NT_LOG(ERR, FILTER, "ERROR: module request to allocate 0 bytes of memory\n");
+	}
+
+	va_end(args);
+
+	mod->base = base;
+	mod->alloced_size = total_bytes;
+
+	return base;
+}
+
+void zero_module_cache(struct common_func_s *mod)
+{
+	memset(mod->base, 0, mod->alloced_size);
+}
+
 int flow_api_backend_init(struct flow_api_backend_s *dev,
 	const struct flow_api_backend_ops *iface,
 	void *be_dev)
@@ -17,12 +90,46 @@  int flow_api_backend_init(struct flow_api_backend_s *dev,
 	dev->max_categories = iface->get_nb_categories(be_dev);
 	dev->max_queues = iface->get_nb_queues(be_dev);
 
+	NT_LOG(DBG,
+		FILTER,
+		"*************** FLOW REGISTER MODULES AND INITIALIZE - SET ALL TO DEFAULT *****************\n");
+
+	/*
+	 * Create Cache and SW, version independent, NIC module representation
+	 */
+	for (unsigned int mod = 0; mod < MOD_COUNT; mod++) {
+		if (!module[mod].present(dev))
+			continue;
+
+		if (module[mod].allocate(dev) == 0 && module[mod].reset(dev) == 0) {
+			/* OK */
+			continue;
+		}
+
+		NT_LOG(ERR,
+			FILTER,
+			"ERROR: Initialization of NIC module failed : [ %s ]\n",
+			module[mod].name);
+		flow_api_backend_done(dev);
+		NT_LOG(ERR,
+			FILTER,
+			"*************** Failed to create Binary Flow API *******************\n");
+		NT_LOG(ERR,
+			FILTER,
+			"******** ERROR ERROR: Binary Flow API will not be available ********\n");
+		NT_LOG(ERR,
+			FILTER,
+			"********************************************************************\n");
+		return -1;
+	}
+
 	return 0;
 }
 
 int flow_api_backend_done(struct flow_api_backend_s *dev)
 {
-	(void)dev;
+	for (unsigned int mod = 0; mod < MOD_COUNT; mod++)
+		module[mod].free(dev);
 
 	return 0;
 }
diff --git a/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c
new file mode 100644
index 0000000000..0c1f37db2b
--- /dev/null
+++ b/drivers/net/ntnic/nthw/flow_api/hw_mod/hw_mod_cat.c
@@ -0,0 +1,985 @@ 
+/*
+ * SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(c) 2023 Napatech A/S
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "hw_mod_backend.h"
+
+#define _MOD_ "CAT"
+#define _VER_ be->cat.ver
+
+static int hw_mod_cat_kce_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count);
+static int hw_mod_cat_kcs_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count);
+static int hw_mod_cat_fte_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count);
+
+bool hw_mod_cat_present(struct flow_api_backend_s *be)
+{
+	return be->iface->get_cat_present(be->be_dev);
+}
+
+int hw_mod_cat_alloc(struct flow_api_backend_s *be)
+{
+	_VER_ = be->iface->get_cat_version(be->be_dev);
+	NT_LOG(DBG, FILTER, "CAT MODULE VERSION  %i.%i\n", VER_MAJOR(_VER_), VER_MINOR(_VER_));
+
+	int nb = be->iface->get_nb_cat_funcs(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(cat_funcs);
+
+	be->cat.nb_cat_funcs = (uint32_t)nb;
+
+	nb = be->iface->get_nb_km_flow_types(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(km_flow_types);
+
+	be->cat.nb_flow_types = (uint32_t)nb;
+
+	nb = be->iface->get_nb_pm_ext(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(pm_ext);
+
+	be->cat.nb_pm_ext = (uint32_t)nb;
+
+	nb = be->iface->get_nb_len(be->be_dev);
+
+	if (nb <= 0)
+		return COUNT_ERROR(len);
+
+	be->cat.nb_len = (uint32_t)nb;
+
+	nb = be->iface->get_kcc_size(be->be_dev);
+
+	if (nb < 0)
+		return COUNT_ERROR(kcc_size);
+
+	be->cat.kcc_size = (uint32_t)nb;
+
+	nb = be->iface->get_kcc_banks(be->be_dev);
+
+	if (nb < 0)
+		return COUNT_ERROR(kcc_banks);
+
+	be->cat.kcc_banks = (uint32_t)nb;
+
+	nb = be->iface->get_nb_cat_km_if_cnt(be->be_dev);
+
+	if (nb < 0)
+		return COUNT_ERROR(km_if_count);
+
+	be->cat.km_if_count = (uint32_t)nb;
+
+	int idx = be->iface->get_nb_cat_km_if_m0(be->be_dev);
+	be->cat.km_if_m0 = idx;
+
+	idx = be->iface->get_nb_cat_km_if_m1(be->be_dev);
+	be->cat.km_if_m1 = idx;
+
+	if (be->cat.kcc_banks)
+		be->cat.kcc_records = be->cat.kcc_size / be->cat.kcc_banks;
+
+	else
+		be->cat.kcc_records = 0;
+
+	be->cat.kcc_id_bit_size = 10;
+
+	switch (_VER_) {
+	case 18:
+		be->cat.cts_num = 11;
+
+		if (!callocate_mod((struct common_func_s *)&be->cat, 12, &be->cat.v18.cfn,
+				be->cat.nb_cat_funcs, sizeof(struct cat_v18_cfn_s),
+				&be->cat.v18.kce, (be->cat.nb_cat_funcs / 8),
+				sizeof(struct cat_v18_kce_s), &be->cat.v18.kcs,
+				be->cat.nb_cat_funcs, sizeof(struct cat_v18_kcs_s),
+				&be->cat.v18.fte,
+				(be->cat.nb_cat_funcs / 8) * be->cat.nb_flow_types * 2,
+				sizeof(struct cat_v18_fte_s),
+
+				&be->cat.v18.cte, be->cat.nb_cat_funcs,
+				sizeof(struct cat_v18_cte_s), &be->cat.v18.cts,
+				be->cat.nb_cat_funcs * ((be->cat.cts_num + 1) / 2),
+				sizeof(struct cat_v18_cts_s), &be->cat.v18.cot,
+				be->max_categories, sizeof(struct cat_v18_cot_s),
+
+				&be->cat.v18.cct, be->max_categories * 4,
+				sizeof(struct cat_v18_cct_s), &be->cat.v18.exo,
+				be->cat.nb_pm_ext, sizeof(struct cat_v18_exo_s),
+				&be->cat.v18.rck, be->cat.nb_pm_ext * 64,
+				sizeof(struct cat_v18_rck_s), &be->cat.v18.len, be->cat.nb_len,
+				sizeof(struct cat_v18_len_s), &be->cat.v18.kcc_cam,
+				be->cat.kcc_size, sizeof(struct cat_v18_kcc_s)))
+			return -1;
+
+		break;
+
+	/* end case 18 */
+	case 21:
+		be->cat.cts_num = 11;
+
+		if (!callocate_mod((struct common_func_s *)&be->cat, 12, &be->cat.v21.cfn,
+				be->cat.nb_cat_funcs, sizeof(struct cat_v21_cfn_s),
+				&be->cat.v21.kce, (be->cat.nb_cat_funcs / 8),
+				sizeof(struct cat_v21_kce_s), &be->cat.v21.kcs,
+				be->cat.nb_cat_funcs, sizeof(struct cat_v21_kcs_s),
+				&be->cat.v21.fte,
+				(be->cat.nb_cat_funcs / 8) * be->cat.nb_flow_types * 4,
+				sizeof(struct cat_v21_fte_s),
+
+				&be->cat.v21.cte, be->cat.nb_cat_funcs,
+				sizeof(struct cat_v18_cte_s), &be->cat.v21.cts,
+				be->cat.nb_cat_funcs * ((be->cat.cts_num + 1) / 2),
+				sizeof(struct cat_v18_cts_s), &be->cat.v21.cot,
+				be->max_categories, sizeof(struct cat_v18_cot_s),
+
+				&be->cat.v21.cct, be->max_categories * 4,
+				sizeof(struct cat_v18_cct_s), &be->cat.v21.exo,
+				be->cat.nb_pm_ext, sizeof(struct cat_v18_exo_s),
+				&be->cat.v21.rck, be->cat.nb_pm_ext * 64,
+				sizeof(struct cat_v18_rck_s), &be->cat.v21.len, be->cat.nb_len,
+				sizeof(struct cat_v18_len_s), &be->cat.v21.kcc_cam,
+				be->cat.kcc_size, sizeof(struct cat_v18_kcc_s)))
+			return -1;
+
+		break;
+
+	/* end case 21 */
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+void hw_mod_cat_free(struct flow_api_backend_s *be)
+{
+	if (be->cat.base) {
+		free(be->cat.base);
+		be->cat.base = NULL;
+	}
+}
+
+static int cfn_reset(struct flow_api_backend_s *be, int i)
+{
+	int err = hw_mod_cat_cfn_set(be, HW_CAT_CFN_PRESET_ALL, i, 0, 0);
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_ISL, i, 0,
+		0xffffffff);	/* accept both ISL or not ISL */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_CFP, i, 0,
+		0xffffffff);	/* accept both CFP or not CFP */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_MAC, i, 0, 0xffffffff);	/* accept all MACs */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_L2, i, 0, 0xffffffff);	/* accept all L2 prot */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_VNTAG, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_VLAN, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_MPLS, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_L3, i, 0, 0xffffffff);	/* accept all L3 prot */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_FRAG, i, 0, 0xffffffff);	/* accept all fragments */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_IP_PROT, i, 0,
+		0xffffffff);	/* IP prot check disabled */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_L4, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TUNNEL, i, 0, 0xffffffff);/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_L2, i, 0, 0xffffffff);/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_VLAN, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_MPLS, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_L3, i, 0, 0xffffffff);/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_FRAG, i, 0, 0xffffffff);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_IP_PROT, i, 0,
+		0xffffffff);	/* inner IP prot check disabled */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PTC_TNL_L4, i, 0, 0xffffffff);/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_CV, i, 0, 3);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_FCS, i, 0, 3);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TRUNC, i, 0,
+		0xffffffff);	/* accept all truncations */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_L3_CS, i, 0, 3);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_L4_CS, i, 0, 3);	/* accept all */
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_PM_OR_INV, i, 0, 1);
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_LC_INV, i, 0, 1);
+	hw_mod_cat_cfn_set(be, HW_CAT_CFN_KM0_OR, i, 0, 0xffffffff);	/* or all */
+
+	if (_VER_ >= 21) {
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_KM1_OR, i, 0, 0xffffffff);	/* or all */
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TNL_L3_CS, i, 0, 0xffffffff);	/* or all */
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TNL_L4_CS, i, 0, 0xffffffff);	/* or all */
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TTL_EXP, i, 0, 0xffffffff);	/* or all */
+		hw_mod_cat_cfn_set(be, HW_CAT_CFN_ERR_TNL_TTL_EXP, i, 0, 0xffffffff);	/* or all */
+	}
+
+	return err;
+}
+
+int hw_mod_cat_reset(struct flow_api_backend_s *be)
+{
+	/* Zero entire cache area */
+	zero_module_cache((struct common_func_s *)(&be->cat));
+
+	NT_LOG(DBG, FILTER, "INIT CAT CFN\n");
+
+	if (hw_mod_cat_cfn_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	if (_VER_ <= 18) {
+		NT_LOG(DBG, FILTER, "INIT CAT KCE\n");
+
+		if (hw_mod_cat_kce_flush(be, KM_FLM_IF_FIRST, 0, 0, ALL_ENTRIES))
+			return -1;
+
+		NT_LOG(DBG, FILTER, "INIT CAT KCS\n");
+
+		if (hw_mod_cat_kcs_flush(be, KM_FLM_IF_FIRST, 0, 0, ALL_ENTRIES))
+			return -1;
+
+		NT_LOG(DBG, FILTER, "INIT CAT FTE\n");
+
+		if (hw_mod_cat_fte_flush(be, KM_FLM_IF_FIRST, 0, 0, ALL_ENTRIES))
+			return -1;
+
+	} else {
+		NT_LOG(DBG, FILTER, "INIT CAT KCE 0\n");
+
+		if (hw_mod_cat_kce_flush(be, KM_FLM_IF_FIRST, be->cat.km_if_m0, 0, ALL_ENTRIES))
+			return -1;
+
+		NT_LOG(DBG, FILTER, "INIT CAT KCS 0\n");
+
+		if (hw_mod_cat_kcs_flush(be, KM_FLM_IF_FIRST, be->cat.km_if_m0, 0, ALL_ENTRIES))
+			return -1;
+
+		NT_LOG(DBG, FILTER, "INIT CAT FTE 0\n");
+
+		if (hw_mod_cat_fte_flush(be, KM_FLM_IF_FIRST, be->cat.km_if_m0, 0, ALL_ENTRIES))
+			return -1;
+
+		if (be->cat.km_if_count > 1) {
+			NT_LOG(DBG, FILTER, "INIT CAT KCE 1\n");
+
+			if (hw_mod_cat_kce_flush(be, KM_FLM_IF_SECOND, be->cat.km_if_m1, 0,
+					ALL_ENTRIES))
+				return -1;
+
+			NT_LOG(DBG, FILTER, "INIT CAT KCS 1\n");
+
+			if (hw_mod_cat_kcs_flush(be, KM_FLM_IF_SECOND, be->cat.km_if_m1, 0,
+					ALL_ENTRIES))
+				return -1;
+
+			NT_LOG(DBG, FILTER, "INIT CAT FTE 1\n");
+
+			if (hw_mod_cat_fte_flush(be, KM_FLM_IF_SECOND, be->cat.km_if_m1, 0,
+					ALL_ENTRIES))
+				return -1;
+		}
+	}
+
+	NT_LOG(DBG, FILTER, "INIT CAT CTE\n");
+
+	if (hw_mod_cat_cte_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT CTS\n");
+
+	if (hw_mod_cat_cts_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT COT\n");
+
+	if (hw_mod_cat_cot_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT CCT\n");
+
+	if (hw_mod_cat_cct_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT EXO\n");
+
+	if (hw_mod_cat_exo_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT RCK\n");
+
+	if (hw_mod_cat_rck_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	NT_LOG(DBG, FILTER, "INIT CAT LEN\n");
+
+	if (hw_mod_cat_len_flush(be, 0, ALL_ENTRIES))
+		return -1;
+
+	if (be->cat.kcc_size) {
+		NT_LOG(DBG, FILTER, "INIT CAT KCC\n");
+
+		if (hw_mod_cat_kcc_flush(be, 0, ALL_ENTRIES))
+			return -1;
+	}
+
+	return 0;
+}
+
+int hw_mod_cat_cfn_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	switch (count) {
+	case ALL_ENTRIES:
+		if (start_idx != 0)
+			return INDEX_TOO_LARGE;
+
+		return be->iface->cat_cfn_flush(be->be_dev, &be->cat, start_idx,
+				be->cat.nb_cat_funcs);
+
+	default:
+		if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs)
+			return INDEX_TOO_LARGE;
+
+		return be->iface->cat_cfn_flush(be->be_dev, &be->cat, start_idx, count);
+	}
+}
+
+static int hw_mod_cat_cfn_mod(struct flow_api_backend_s *be, enum hw_cat_e field, int index,
+	int word_off, uint32_t *value, int get)
+{
+	if ((unsigned int)index >= be->cat.nb_cat_funcs)
+		return INDEX_TOO_LARGE;
+
+	switch (_VER_) {
+	case 18:
+		switch (field) {
+		case HW_CAT_CFN_SET_ALL_DEFAULTS:
+			if (get)
+				return UNSUP_FIELD;
+
+			return cfn_reset(be, index);
+
+		case HW_CAT_CFN_PRESET_ALL:
+			if (get)
+				return UNSUP_FIELD;
+
+			memset(&be->cat.v18.cfn[index], (uint8_t)*value,
+				sizeof(struct cat_v18_cfn_s));
+			break;
+
+		case HW_CAT_CFN_COMPARE:
+			if (!get)
+				return UNSUP_FIELD;
+
+			if ((unsigned int)word_off >= be->cat.nb_cat_funcs)
+				return INDEX_TOO_LARGE;
+
+			DO_COMPARE_INDEXS(be->cat.v18.cfn, struct cat_v18_cfn_s, index, word_off);
+			break;
+
+		case HW_CAT_CFN_FIND:
+			if (!get)
+				return UNSUP_FIELD;
+
+			if ((unsigned int)word_off >= be->cat.nb_cat_funcs)
+				return INDEX_TOO_LARGE;
+
+			FIND_EQUAL_INDEX(be->cat.v18.cfn, struct cat_v18_cfn_s, index, word_off,
+				be->cat.nb_cat_funcs);
+			break;
+
+		case HW_CAT_CFN_ENABLE:
+			GET_SET(be->cat.v18.cfn[index].enable, value);
+			break;
+
+		case HW_CAT_CFN_INV:
+			GET_SET(be->cat.v18.cfn[index].inv, value);
+			break;
+
+		case HW_CAT_CFN_PTC_INV:
+			GET_SET(be->cat.v18.cfn[index].ptc_inv, value);
+			break;
+
+		case HW_CAT_CFN_PTC_ISL:
+			GET_SET(be->cat.v18.cfn[index].ptc_isl, value);
+			break;
+
+		case HW_CAT_CFN_PTC_CFP:
+			GET_SET(be->cat.v18.cfn[index].ptc_cfp, value);
+			break;
+
+		case HW_CAT_CFN_PTC_MAC:
+			GET_SET(be->cat.v18.cfn[index].ptc_mac, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L2:
+			GET_SET(be->cat.v18.cfn[index].ptc_l2, value);
+			break;
+
+		case HW_CAT_CFN_PTC_VNTAG:
+			GET_SET(be->cat.v18.cfn[index].ptc_vntag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_VLAN:
+			GET_SET(be->cat.v18.cfn[index].ptc_vlan, value);
+			break;
+
+		case HW_CAT_CFN_PTC_MPLS:
+			GET_SET(be->cat.v18.cfn[index].ptc_mpls, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L3:
+			GET_SET(be->cat.v18.cfn[index].ptc_l3, value);
+			break;
+
+		case HW_CAT_CFN_PTC_FRAG:
+			GET_SET(be->cat.v18.cfn[index].ptc_frag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_IP_PROT:
+			GET_SET(be->cat.v18.cfn[index].ptc_ip_prot, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L4:
+			GET_SET(be->cat.v18.cfn[index].ptc_l4, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TUNNEL:
+			GET_SET(be->cat.v18.cfn[index].ptc_tunnel, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L2:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_l2, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_VLAN:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_vlan, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_MPLS:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_mpls, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L3:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_l3, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_FRAG:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_frag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_IP_PROT:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_ip_prot, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L4:
+			GET_SET(be->cat.v18.cfn[index].ptc_tnl_l4, value);
+			break;
+
+		case HW_CAT_CFN_ERR_INV:
+			GET_SET(be->cat.v18.cfn[index].err_inv, value);
+			break;
+
+		case HW_CAT_CFN_ERR_CV:
+			GET_SET(be->cat.v18.cfn[index].err_cv, value);
+			break;
+
+		case HW_CAT_CFN_ERR_FCS:
+			GET_SET(be->cat.v18.cfn[index].err_fcs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TRUNC:
+			GET_SET(be->cat.v18.cfn[index].err_trunc, value);
+			break;
+
+		case HW_CAT_CFN_ERR_L3_CS:
+			GET_SET(be->cat.v18.cfn[index].err_l3_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_L4_CS:
+			GET_SET(be->cat.v18.cfn[index].err_l4_cs, value);
+			break;
+
+		case HW_CAT_CFN_MAC_PORT:
+			GET_SET(be->cat.v18.cfn[index].mac_port, value);
+			break;
+
+		case HW_CAT_CFN_PM_CMP:
+			if (word_off > 1)
+				return WORD_OFF_TOO_LARGE;
+
+			GET_SET(be->cat.v18.cfn[index].pm_cmp[word_off], value);
+			break;
+
+		case HW_CAT_CFN_PM_DCT:
+			GET_SET(be->cat.v18.cfn[index].pm_dct, value);
+			break;
+
+		case HW_CAT_CFN_PM_EXT_INV:
+			GET_SET(be->cat.v18.cfn[index].pm_ext_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_CMB:
+			GET_SET(be->cat.v18.cfn[index].pm_cmb, value);
+			break;
+
+		case HW_CAT_CFN_PM_AND_INV:
+			GET_SET(be->cat.v18.cfn[index].pm_and_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_OR_INV:
+			GET_SET(be->cat.v18.cfn[index].pm_or_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_INV:
+			GET_SET(be->cat.v18.cfn[index].pm_inv, value);
+			break;
+
+		case HW_CAT_CFN_LC:
+			GET_SET(be->cat.v18.cfn[index].lc, value);
+			break;
+
+		case HW_CAT_CFN_LC_INV:
+			GET_SET(be->cat.v18.cfn[index].lc_inv, value);
+			break;
+
+		case HW_CAT_CFN_KM0_OR:
+			GET_SET(be->cat.v18.cfn[index].km_or, value);
+			break;
+
+		default:
+			return UNSUP_FIELD;
+		}
+
+		break;
+
+	/* end case 18 */
+	case 21:
+		switch (field) {
+		case HW_CAT_CFN_SET_ALL_DEFAULTS:
+			if (get)
+				return UNSUP_FIELD;
+
+			return cfn_reset(be, index);
+
+		case HW_CAT_CFN_PRESET_ALL:
+			if (get)
+				return UNSUP_FIELD;
+
+			memset(&be->cat.v21.cfn[index], (uint8_t)*value,
+				sizeof(struct cat_v21_cfn_s));
+			break;
+
+		case HW_CAT_CFN_COMPARE:
+			if (!get)
+				return UNSUP_FIELD;
+
+			if ((unsigned int)word_off >= be->cat.nb_cat_funcs)
+				return INDEX_TOO_LARGE;
+
+			DO_COMPARE_INDEXS(be->cat.v21.cfn, struct cat_v21_cfn_s, index, word_off);
+			break;
+
+		case HW_CAT_CFN_FIND:
+			if (!get)
+				return UNSUP_FIELD;
+
+			if ((unsigned int)word_off >= be->cat.nb_cat_funcs)
+				return INDEX_TOO_LARGE;
+
+			FIND_EQUAL_INDEX(be->cat.v21.cfn, struct cat_v21_cfn_s, index, word_off,
+				be->cat.nb_cat_funcs);
+			break;
+
+		case HW_CAT_CFN_COPY_FROM:
+			if (get)
+				return UNSUP_FIELD;
+
+			memcpy(&be->cat.v21.cfn[index], &be->cat.v21.cfn[*value],
+				sizeof(struct cat_v21_cfn_s));
+			break;
+
+		case HW_CAT_CFN_ENABLE:
+			GET_SET(be->cat.v21.cfn[index].enable, value);
+			break;
+
+		case HW_CAT_CFN_INV:
+			GET_SET(be->cat.v21.cfn[index].inv, value);
+			break;
+
+		case HW_CAT_CFN_PTC_INV:
+			GET_SET(be->cat.v21.cfn[index].ptc_inv, value);
+			break;
+
+		case HW_CAT_CFN_PTC_ISL:
+			GET_SET(be->cat.v21.cfn[index].ptc_isl, value);
+			break;
+
+		case HW_CAT_CFN_PTC_CFP:
+			GET_SET(be->cat.v21.cfn[index].ptc_cfp, value);
+			break;
+
+		case HW_CAT_CFN_PTC_MAC:
+			GET_SET(be->cat.v21.cfn[index].ptc_mac, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L2:
+			GET_SET(be->cat.v21.cfn[index].ptc_l2, value);
+			break;
+
+		case HW_CAT_CFN_PTC_VNTAG:
+			GET_SET(be->cat.v21.cfn[index].ptc_vntag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_VLAN:
+			GET_SET(be->cat.v21.cfn[index].ptc_vlan, value);
+			break;
+
+		case HW_CAT_CFN_PTC_MPLS:
+			GET_SET(be->cat.v21.cfn[index].ptc_mpls, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L3:
+			GET_SET(be->cat.v21.cfn[index].ptc_l3, value);
+			break;
+
+		case HW_CAT_CFN_PTC_FRAG:
+			GET_SET(be->cat.v21.cfn[index].ptc_frag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_IP_PROT:
+			GET_SET(be->cat.v21.cfn[index].ptc_ip_prot, value);
+			break;
+
+		case HW_CAT_CFN_PTC_L4:
+			GET_SET(be->cat.v21.cfn[index].ptc_l4, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TUNNEL:
+			GET_SET(be->cat.v21.cfn[index].ptc_tunnel, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L2:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_l2, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_VLAN:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_vlan, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_MPLS:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_mpls, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L3:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_l3, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_FRAG:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_frag, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_IP_PROT:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_ip_prot, value);
+			break;
+
+		case HW_CAT_CFN_PTC_TNL_L4:
+			GET_SET(be->cat.v21.cfn[index].ptc_tnl_l4, value);
+			break;
+
+		case HW_CAT_CFN_ERR_INV:
+			GET_SET(be->cat.v21.cfn[index].err_inv, value);
+			break;
+
+		case HW_CAT_CFN_ERR_CV:
+			GET_SET(be->cat.v21.cfn[index].err_cv, value);
+			break;
+
+		case HW_CAT_CFN_ERR_FCS:
+			GET_SET(be->cat.v21.cfn[index].err_fcs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TRUNC:
+			GET_SET(be->cat.v21.cfn[index].err_trunc, value);
+			break;
+
+		case HW_CAT_CFN_ERR_L3_CS:
+			GET_SET(be->cat.v21.cfn[index].err_l3_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_L4_CS:
+			GET_SET(be->cat.v21.cfn[index].err_l4_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TNL_L3_CS:
+			GET_SET(be->cat.v21.cfn[index].err_tnl_l3_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TNL_L4_CS:
+			GET_SET(be->cat.v21.cfn[index].err_tnl_l4_cs, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TTL_EXP:
+			GET_SET(be->cat.v21.cfn[index].err_ttl_exp, value);
+			break;
+
+		case HW_CAT_CFN_ERR_TNL_TTL_EXP:
+			GET_SET(be->cat.v21.cfn[index].err_tnl_ttl_exp, value);
+			break;
+
+		case HW_CAT_CFN_MAC_PORT:
+			GET_SET(be->cat.v21.cfn[index].mac_port, value);
+			break;
+
+		case HW_CAT_CFN_PM_CMP:
+			if (word_off > 1)
+				return WORD_OFF_TOO_LARGE;
+
+			GET_SET(be->cat.v21.cfn[index].pm_cmp[word_off], value);
+			break;
+
+		case HW_CAT_CFN_PM_DCT:
+			GET_SET(be->cat.v21.cfn[index].pm_dct, value);
+			break;
+
+		case HW_CAT_CFN_PM_EXT_INV:
+			GET_SET(be->cat.v21.cfn[index].pm_ext_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_CMB:
+			GET_SET(be->cat.v21.cfn[index].pm_cmb, value);
+			break;
+
+		case HW_CAT_CFN_PM_AND_INV:
+			GET_SET(be->cat.v21.cfn[index].pm_and_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_OR_INV:
+			GET_SET(be->cat.v21.cfn[index].pm_or_inv, value);
+			break;
+
+		case HW_CAT_CFN_PM_INV:
+			GET_SET(be->cat.v21.cfn[index].pm_inv, value);
+			break;
+
+		case HW_CAT_CFN_LC:
+			GET_SET(be->cat.v21.cfn[index].lc, value);
+			break;
+
+		case HW_CAT_CFN_LC_INV:
+			GET_SET(be->cat.v21.cfn[index].lc_inv, value);
+			break;
+
+		case HW_CAT_CFN_KM0_OR:
+			GET_SET(be->cat.v21.cfn[index].km0_or, value);
+			break;
+
+		case HW_CAT_CFN_KM1_OR:
+			GET_SET(be->cat.v21.cfn[index].km1_or, value);
+			break;
+
+		default:
+			return UNSUP_FIELD;
+		}
+
+		break;
+
+	/* end case 21 */
+
+	default:
+		return UNSUP_VER;
+	}
+
+	return 0;
+}
+
+int hw_mod_cat_cfn_set(struct flow_api_backend_s *be, enum hw_cat_e field, int index, int word_off,
+	uint32_t value)
+{
+	return hw_mod_cat_cfn_mod(be, field, index, word_off, &value, 0);
+}
+
+static inline int find_km_flm_module_interface_index(struct flow_api_backend_s *be,
+	enum km_flm_if_select_e if_num, int km_if_id)
+{
+	int km_if_idx;
+
+	if (_VER_ == 18) {
+		km_if_idx = 0;
+
+	} else {
+		if (if_num == KM_FLM_IF_SECOND)
+			if (be->cat.km_if_m1 == km_if_id)
+				km_if_idx = 1;
+
+			else
+				return UNSUP_FIELD;
+
+		else if (be->cat.km_if_m0 == km_if_id)
+			km_if_idx = 0;
+
+		else if (be->cat.km_if_m1 == km_if_id)
+			km_if_idx = 1;
+
+		else
+			return UNSUP_FIELD;
+	}
+
+	return km_if_idx;
+}
+
+/*
+ * KCE
+ */
+
+static int hw_mod_cat_kce_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count)
+{
+	/* writes 8 bits - one for each cfn - at a time */
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs / 8;
+
+	if ((unsigned int)(start_idx + count) > (be->cat.nb_cat_funcs / 8))
+		return INDEX_TOO_LARGE;
+
+	/* find KM module */
+	int km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id);
+
+	if (km_if_idx < 0)
+		return km_if_idx;
+
+	return be->iface->cat_kce_flush(be->be_dev, &be->cat, km_if_idx, start_idx, count);
+}
+
+/*
+ * KCS
+ */
+static int hw_mod_cat_kcs_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs)
+		return INDEX_TOO_LARGE;
+
+	/* find KM module */
+	int km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id);
+
+	if (km_if_idx < 0)
+		return km_if_idx;
+
+	return be->iface->cat_kcs_flush(be->be_dev, &be->cat, km_if_idx, start_idx, count);
+}
+
+/*
+ * FTE
+ */
+static int hw_mod_cat_fte_flush(struct flow_api_backend_s *be, enum km_flm_if_select_e if_num,
+	int km_if_id, int start_idx, int count)
+{
+	const uint32_t key_cnt = (_VER_ >= 20) ? 4 : 2;
+
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs / 8 * be->cat.nb_flow_types * key_cnt;
+
+	if ((unsigned int)(start_idx + count) >
+		(be->cat.nb_cat_funcs / 8 * be->cat.nb_flow_types * key_cnt)) {
+		return INDEX_TOO_LARGE;
+	}
+
+	/* find KM module */
+	int km_if_idx = find_km_flm_module_interface_index(be, if_num, km_if_id);
+
+	if (km_if_idx < 0)
+		return km_if_idx;
+
+	return be->iface->cat_fte_flush(be->be_dev, &be->cat, km_if_idx, start_idx, count);
+}
+
+int hw_mod_cat_cte_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_cte_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_cts_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	int addr_size = (_VER_ < 15) ? 8 : ((be->cat.cts_num + 1) / 2);
+
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs * addr_size;
+
+	if ((unsigned int)(start_idx + count) > (be->cat.nb_cat_funcs * addr_size))
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_cts_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_cot_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->max_categories;
+
+	if ((unsigned int)(start_idx + count) > be->max_categories)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_cot_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_cct_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_cat_funcs * 4;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_cat_funcs * 4)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_cct_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_kcc_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.kcc_size;
+
+	if ((unsigned int)(start_idx + count) > be->cat.kcc_size)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_kcc_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_exo_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_pm_ext;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_pm_ext)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_exo_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_rck_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_pm_ext * 64;
+
+	if ((unsigned int)(start_idx + count) > (be->cat.nb_pm_ext * 64))
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_rck_flush(be->be_dev, &be->cat, start_idx, count);
+}
+
+int hw_mod_cat_len_flush(struct flow_api_backend_s *be, int start_idx, int count)
+{
+	if (count == ALL_ENTRIES)
+		count = be->cat.nb_len;
+
+	if ((unsigned int)(start_idx + count) > be->cat.nb_len)
+		return INDEX_TOO_LARGE;
+
+	return be->iface->cat_len_flush(be->be_dev, &be->cat, start_idx, count);
+}
diff --git a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
index cbebcff541..4efd5aa2f8 100644
--- a/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
+++ b/drivers/net/ntnic/nthw/supported/nthw_fpga_9563_055_049_0000.c
@@ -9,6 +9,267 @@ 
 
 #include "nthw_register.h"
 
+static nthw_fpga_field_init_s cat_cct_ctrl_fields[] = {
+	{ CAT_CCT_CTRL_ADR, 8, 0, 0x0000 },
+	{ CAT_CCT_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cct_data_fields[] = {
+	{ CAT_CCT_DATA_COLOR, 32, 0, 0x0000 },
+	{ CAT_CCT_DATA_KM, 4, 32, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cfn_ctrl_fields[] = {
+	{ CAT_CFN_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_CFN_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cfn_data_fields[] = {
+	{ CAT_CFN_DATA_ENABLE, 1, 0, 0x0000 },
+	{ CAT_CFN_DATA_ERR_CV, 2, 99, 0x0000 },
+	{ CAT_CFN_DATA_ERR_FCS, 2, 101, 0x0000 },
+	{ CAT_CFN_DATA_ERR_INV, 1, 98, 0x0000 },
+	{ CAT_CFN_DATA_ERR_L3_CS, 2, 105, 0x0000 },
+	{ CAT_CFN_DATA_ERR_L4_CS, 2, 107, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TNL_L3_CS, 2, 109, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TNL_L4_CS, 2, 111, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TNL_TTL_EXP, 2, 115, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TRUNC, 2, 103, 0x0000 },
+	{ CAT_CFN_DATA_ERR_TTL_EXP, 2, 113, 0x0000 },
+	{ CAT_CFN_DATA_INV, 1, 1, 0x0000 },
+	{ CAT_CFN_DATA_KM0_OR, 3, 173, 0x0000 },
+	{ CAT_CFN_DATA_KM1_OR, 3, 176, 0x0000 },
+	{ CAT_CFN_DATA_LC, 8, 164, 0x0000 },
+	{ CAT_CFN_DATA_LC_INV, 1, 172, 0x0000 },
+	{ CAT_CFN_DATA_MAC_PORT, 2, 117, 0x0000 },
+	{ CAT_CFN_DATA_PM_AND_INV, 1, 161, 0x0000 },
+	{ CAT_CFN_DATA_PM_CMB, 4, 157, 0x0000 },
+	{ CAT_CFN_DATA_PM_CMP, 32, 119, 0x0000 },
+	{ CAT_CFN_DATA_PM_DCT, 2, 151, 0x0000 },
+	{ CAT_CFN_DATA_PM_EXT_INV, 4, 153, 0x0000 },
+	{ CAT_CFN_DATA_PM_INV, 1, 163, 0x0000 },
+	{ CAT_CFN_DATA_PM_OR_INV, 1, 162, 0x0000 },
+	{ CAT_CFN_DATA_PTC_CFP, 2, 5, 0x0000 },
+	{ CAT_CFN_DATA_PTC_FRAG, 4, 36, 0x0000 },
+	{ CAT_CFN_DATA_PTC_INV, 1, 2, 0x0000 },
+	{ CAT_CFN_DATA_PTC_IP_PROT, 8, 40, 0x0000 },
+	{ CAT_CFN_DATA_PTC_ISL, 2, 3, 0x0000 },
+	{ CAT_CFN_DATA_PTC_L2, 7, 12, 0x0000 },
+	{ CAT_CFN_DATA_PTC_L3, 3, 33, 0x0000 },
+	{ CAT_CFN_DATA_PTC_L4, 5, 48, 0x0000 },
+	{ CAT_CFN_DATA_PTC_MAC, 5, 7, 0x0000 },
+	{ CAT_CFN_DATA_PTC_MPLS, 8, 25, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_FRAG, 4, 81, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_IP_PROT, 8, 85, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_L2, 2, 64, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_L3, 3, 78, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_L4, 5, 93, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_MPLS, 8, 70, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TNL_VLAN, 4, 66, 0x0000 },
+	{ CAT_CFN_DATA_PTC_TUNNEL, 11, 53, 0x0000 },
+	{ CAT_CFN_DATA_PTC_VLAN, 4, 21, 0x0000 },
+	{ CAT_CFN_DATA_PTC_VNTAG, 2, 19, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cot_ctrl_fields[] = {
+	{ CAT_COT_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_COT_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cot_data_fields[] = {
+	{ CAT_COT_DATA_COLOR, 32, 0, 0x0000 },
+	{ CAT_COT_DATA_KM, 4, 32, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cte_ctrl_fields[] = {
+	{ CAT_CTE_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_CTE_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cte_data_fields[] = {
+	{ CAT_CTE_DATA_COL_ENABLE, 1, 0, 0x0000 }, { CAT_CTE_DATA_COR_ENABLE, 1, 1, 0x0000 },
+	{ CAT_CTE_DATA_EPP_ENABLE, 1, 9, 0x0000 }, { CAT_CTE_DATA_HSH_ENABLE, 1, 2, 0x0000 },
+	{ CAT_CTE_DATA_HST_ENABLE, 1, 8, 0x0000 }, { CAT_CTE_DATA_IPF_ENABLE, 1, 4, 0x0000 },
+	{ CAT_CTE_DATA_MSK_ENABLE, 1, 7, 0x0000 }, { CAT_CTE_DATA_PDB_ENABLE, 1, 6, 0x0000 },
+	{ CAT_CTE_DATA_QSL_ENABLE, 1, 3, 0x0000 }, { CAT_CTE_DATA_SLC_ENABLE, 1, 5, 0x0000 },
+	{ CAT_CTE_DATA_TPE_ENABLE, 1, 10, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cts_ctrl_fields[] = {
+	{ CAT_CTS_CTRL_ADR, 9, 0, 0x0000 },
+	{ CAT_CTS_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_cts_data_fields[] = {
+	{ CAT_CTS_DATA_CAT_A, 6, 0, 0x0000 },
+	{ CAT_CTS_DATA_CAT_B, 6, 6, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_dct_ctrl_fields[] = {
+	{ CAT_DCT_CTRL_ADR, 13, 0, 0x0000 },
+	{ CAT_DCT_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_dct_data_fields[] = {
+	{ CAT_DCT_DATA_RES, 16, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_dct_sel_fields[] = {
+	{ CAT_DCT_SEL_LU, 2, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_exo_ctrl_fields[] = {
+	{ CAT_EXO_CTRL_ADR, 2, 0, 0x0000 },
+	{ CAT_EXO_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_exo_data_fields[] = {
+	{ CAT_EXO_DATA_DYN, 5, 0, 0x0000 },
+	{ CAT_EXO_DATA_OFS, 11, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_fte0_ctrl_fields[] = {
+	{ CAT_FTE0_CTRL_ADR, 9, 0, 0x0000 },
+	{ CAT_FTE0_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_fte0_data_fields[] = {
+	{ CAT_FTE0_DATA_ENABLE, 8, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_fte1_ctrl_fields[] = {
+	{ CAT_FTE1_CTRL_ADR, 9, 0, 0x0000 },
+	{ CAT_FTE1_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_fte1_data_fields[] = {
+	{ CAT_FTE1_DATA_ENABLE, 8, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_join_fields[] = {
+	{ CAT_JOIN_J1, 2, 0, 0x0000 },
+	{ CAT_JOIN_J2, 1, 8, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcc_ctrl_fields[] = {
+	{ CAT_KCC_CTRL_ADR, 11, 0, 0x0000 },
+	{ CAT_KCC_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcc_data_fields[] = {
+	{ CAT_KCC_DATA_CATEGORY, 8, 64, 0x0000 },
+	{ CAT_KCC_DATA_ID, 12, 72, 0x0000 },
+	{ CAT_KCC_DATA_KEY, 64, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kce0_ctrl_fields[] = {
+	{ CAT_KCE0_CTRL_ADR, 3, 0, 0x0000 },
+	{ CAT_KCE0_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kce0_data_fields[] = {
+	{ CAT_KCE0_DATA_ENABLE, 8, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kce1_ctrl_fields[] = {
+	{ CAT_KCE1_CTRL_ADR, 3, 0, 0x0000 },
+	{ CAT_KCE1_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kce1_data_fields[] = {
+	{ CAT_KCE1_DATA_ENABLE, 8, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcs0_ctrl_fields[] = {
+	{ CAT_KCS0_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_KCS0_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcs0_data_fields[] = {
+	{ CAT_KCS0_DATA_CATEGORY, 6, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcs1_ctrl_fields[] = {
+	{ CAT_KCS1_CTRL_ADR, 6, 0, 0x0000 },
+	{ CAT_KCS1_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_kcs1_data_fields[] = {
+	{ CAT_KCS1_DATA_CATEGORY, 6, 0, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_len_ctrl_fields[] = {
+	{ CAT_LEN_CTRL_ADR, 3, 0, 0x0000 },
+	{ CAT_LEN_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_len_data_fields[] = {
+	{ CAT_LEN_DATA_DYN1, 5, 28, 0x0000 }, { CAT_LEN_DATA_DYN2, 5, 33, 0x0000 },
+	{ CAT_LEN_DATA_INV, 1, 38, 0x0000 }, { CAT_LEN_DATA_LOWER, 14, 0, 0x0000 },
+	{ CAT_LEN_DATA_UPPER, 14, 14, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_rck_ctrl_fields[] = {
+	{ CAT_RCK_CTRL_ADR, 8, 0, 0x0000 },
+	{ CAT_RCK_CTRL_CNT, 16, 16, 0x0000 },
+};
+
+static nthw_fpga_field_init_s cat_rck_data_fields[] = {
+	{ CAT_RCK_DATA_CM0U, 1, 1, 0x0000 }, { CAT_RCK_DATA_CM1U, 1, 5, 0x0000 },
+	{ CAT_RCK_DATA_CM2U, 1, 9, 0x0000 }, { CAT_RCK_DATA_CM3U, 1, 13, 0x0000 },
+	{ CAT_RCK_DATA_CM4U, 1, 17, 0x0000 }, { CAT_RCK_DATA_CM5U, 1, 21, 0x0000 },
+	{ CAT_RCK_DATA_CM6U, 1, 25, 0x0000 }, { CAT_RCK_DATA_CM7U, 1, 29, 0x0000 },
+	{ CAT_RCK_DATA_CML0, 1, 0, 0x0000 }, { CAT_RCK_DATA_CML1, 1, 4, 0x0000 },
+	{ CAT_RCK_DATA_CML2, 1, 8, 0x0000 }, { CAT_RCK_DATA_CML3, 1, 12, 0x0000 },
+	{ CAT_RCK_DATA_CML4, 1, 16, 0x0000 }, { CAT_RCK_DATA_CML5, 1, 20, 0x0000 },
+	{ CAT_RCK_DATA_CML6, 1, 24, 0x0000 }, { CAT_RCK_DATA_CML7, 1, 28, 0x0000 },
+	{ CAT_RCK_DATA_SEL0, 1, 2, 0x0000 }, { CAT_RCK_DATA_SEL1, 1, 6, 0x0000 },
+	{ CAT_RCK_DATA_SEL2, 1, 10, 0x0000 }, { CAT_RCK_DATA_SEL3, 1, 14, 0x0000 },
+	{ CAT_RCK_DATA_SEL4, 1, 18, 0x0000 }, { CAT_RCK_DATA_SEL5, 1, 22, 0x0000 },
+	{ CAT_RCK_DATA_SEL6, 1, 26, 0x0000 }, { CAT_RCK_DATA_SEL7, 1, 30, 0x0000 },
+	{ CAT_RCK_DATA_SEU0, 1, 3, 0x0000 }, { CAT_RCK_DATA_SEU1, 1, 7, 0x0000 },
+	{ CAT_RCK_DATA_SEU2, 1, 11, 0x0000 }, { CAT_RCK_DATA_SEU3, 1, 15, 0x0000 },
+	{ CAT_RCK_DATA_SEU4, 1, 19, 0x0000 }, { CAT_RCK_DATA_SEU5, 1, 23, 0x0000 },
+	{ CAT_RCK_DATA_SEU6, 1, 27, 0x0000 }, { CAT_RCK_DATA_SEU7, 1, 31, 0x0000 },
+};
+
+static nthw_fpga_register_init_s cat_registers[] = {
+	{ CAT_CCT_CTRL, 30, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cct_ctrl_fields },
+	{ CAT_CCT_DATA, 31, 36, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cct_data_fields },
+	{ CAT_CFN_CTRL, 10, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cfn_ctrl_fields },
+	{ CAT_CFN_DATA, 11, 179, NTHW_FPGA_REG_TYPE_WO, 0, 44, cat_cfn_data_fields },
+	{ CAT_COT_CTRL, 28, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cot_ctrl_fields },
+	{ CAT_COT_DATA, 29, 36, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cot_data_fields },
+	{ CAT_CTE_CTRL, 24, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cte_ctrl_fields },
+	{ CAT_CTE_DATA, 25, 11, NTHW_FPGA_REG_TYPE_WO, 0, 11, cat_cte_data_fields },
+	{ CAT_CTS_CTRL, 26, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cts_ctrl_fields },
+	{ CAT_CTS_DATA, 27, 12, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_cts_data_fields },
+	{ CAT_DCT_CTRL, 6, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_dct_ctrl_fields },
+	{ CAT_DCT_DATA, 7, 16, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_dct_data_fields },
+	{ CAT_DCT_SEL, 4, 2, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_dct_sel_fields },
+	{ CAT_EXO_CTRL, 0, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_exo_ctrl_fields },
+	{ CAT_EXO_DATA, 1, 27, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_exo_data_fields },
+	{ CAT_FTE0_CTRL, 16, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_fte0_ctrl_fields },
+	{ CAT_FTE0_DATA, 17, 8, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_fte0_data_fields },
+	{ CAT_FTE1_CTRL, 22, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_fte1_ctrl_fields },
+	{ CAT_FTE1_DATA, 23, 8, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_fte1_data_fields },
+	{ CAT_JOIN, 5, 9, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_join_fields },
+	{ CAT_KCC_CTRL, 32, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kcc_ctrl_fields },
+	{ CAT_KCC_DATA, 33, 84, NTHW_FPGA_REG_TYPE_WO, 0, 3, cat_kcc_data_fields },
+	{ CAT_KCE0_CTRL, 12, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kce0_ctrl_fields },
+	{ CAT_KCE0_DATA, 13, 8, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_kce0_data_fields },
+	{ CAT_KCE1_CTRL, 18, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kce1_ctrl_fields },
+	{ CAT_KCE1_DATA, 19, 8, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_kce1_data_fields },
+	{ CAT_KCS0_CTRL, 14, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kcs0_ctrl_fields },
+	{ CAT_KCS0_DATA, 15, 6, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_kcs0_data_fields },
+	{ CAT_KCS1_CTRL, 20, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_kcs1_ctrl_fields },
+	{ CAT_KCS1_DATA, 21, 6, NTHW_FPGA_REG_TYPE_WO, 0, 1, cat_kcs1_data_fields },
+	{ CAT_LEN_CTRL, 8, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_len_ctrl_fields },
+	{ CAT_LEN_DATA, 9, 39, NTHW_FPGA_REG_TYPE_WO, 0, 5, cat_len_data_fields },
+	{ CAT_RCK_CTRL, 2, 32, NTHW_FPGA_REG_TYPE_WO, 0, 2, cat_rck_ctrl_fields },
+	{ CAT_RCK_DATA, 3, 32, NTHW_FPGA_REG_TYPE_WO, 0, 32, cat_rck_data_fields },
+};
+
 static nthw_fpga_field_init_s gfg_burstsize0_fields[] = {
 	{ GFG_BURSTSIZE0_VAL, 24, 0, 0 },
 };
@@ -1037,6 +1298,7 @@  static nthw_fpga_register_init_s rst9563_registers[] = {
 };
 
 static nthw_fpga_module_init_s fpga_modules[] = {
+	{ MOD_CAT, 0, MOD_CAT, 0, 21, NTHW_FPGA_BUS_TYPE_RAB1, 768, 34, cat_registers },
 	{ MOD_GFG, 0, MOD_GFG, 1, 1, NTHW_FPGA_BUS_TYPE_RAB2, 8704, 10, gfg_registers },
 	{ MOD_GMF, 0, MOD_GMF, 2, 5, NTHW_FPGA_BUS_TYPE_RAB2, 9216, 12, gmf_registers },
 	{ MOD_GMF, 1, MOD_GMF, 2, 5, NTHW_FPGA_BUS_TYPE_RAB2, 9728, 12, gmf_registers },
@@ -1226,5 +1488,5 @@  static nthw_fpga_prod_param_s product_parameters[] = {
 };
 
 nthw_fpga_prod_init_s nthw_fpga_9563_055_049_0000 = {
-	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 15, fpga_modules,
+	200, 9563, 55, 49, 0, 0, 1726740521, 152, product_parameters, 16, fpga_modules,
 };