msm: ipa4: add IPv6CT support

IPAv4 HW presents new IPv6 connection tracking functionality.
This change adds SW support of this feature.

Change-Id: I7545af08f090405db80bbd8c10223ca7521080d9
Acked-by: Dmitry Kogan <dmitryk@qti.qualcomm.com>
Signed-off-by: Amir Levy <alevy@codeaurora.org>
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile b/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile
index 67e491b..869ee7e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/Makefile
@@ -1,3 +1,3 @@
 obj-$(CONFIG_IPA3) += ipa_hal.o
 
-ipa_hal-y := ipahal.o ipahal_reg.o ipahal_fltrt.o ipahal_hw_stats.o
+ipa_hal-y := ipahal.o ipahal_reg.o ipahal_fltrt.o ipahal_hw_stats.o ipahal_nat.o
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
index a8d5342..d015b22 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.c
@@ -16,7 +16,7 @@
 #include "ipahal_reg_i.h"
 #include "ipahal_fltrt_i.h"
 #include "ipahal_hw_stats_i.h"
-
+#include "ipahal_nat_i.h"
 
 struct ipahal_context *ipahal_ctx;
 
@@ -35,6 +35,7 @@
 	__stringify(IPA_IMM_CMD_IP_PACKET_TAG_STATUS),
 	__stringify(IPA_IMM_CMD_DMA_TASK_32B_ADDR),
 	__stringify(IPA_IMM_CMD_TABLE_DMA),
+	__stringify(IPA_IMM_CMD_IP_V6_CT_INIT)
 };
 
 static const char *ipahal_pkt_status_exception_to_str
@@ -352,8 +353,8 @@
 {
 	struct ipahal_imm_cmd_pyld *pyld;
 	struct ipa_imm_cmd_hw_nat_dma *data;
-	struct ipahal_imm_cmd_nat_dma *nat_params =
-		(struct ipahal_imm_cmd_nat_dma *)params;
+	struct ipahal_imm_cmd_table_dma *nat_params =
+		(struct ipahal_imm_cmd_table_dma *)params;
 
 	pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
 	if (unlikely(!pyld)) {
@@ -519,24 +520,55 @@
 	pyld->len = sizeof(*data);
 	data = (struct ipa_imm_cmd_hw_ip_v4_nat_init *)pyld->data;
 
-	data->ipv4_rules_addr = nat4_params->ipv4_rules_addr;
+	data->ipv4_rules_addr = nat4_params->table_init.base_table_addr;
 	data->ipv4_expansion_rules_addr =
-		nat4_params->ipv4_expansion_rules_addr;
+		nat4_params->table_init.expansion_table_addr;
 	data->index_table_addr = nat4_params->index_table_addr;
 	data->index_table_expansion_addr =
 		nat4_params->index_table_expansion_addr;
-	data->table_index = nat4_params->table_index;
+	data->table_index = nat4_params->table_init.table_index;
 	data->ipv4_rules_addr_type =
-		nat4_params->ipv4_rules_addr_shared ? 1 : 0;
+		nat4_params->table_init.base_table_addr_shared ? 1 : 0;
 	data->ipv4_expansion_rules_addr_type =
-		nat4_params->ipv4_expansion_rules_addr_shared ? 1 : 0;
+		nat4_params->table_init.expansion_table_addr_shared ? 1 : 0;
 	data->index_table_addr_type =
 		nat4_params->index_table_addr_shared ? 1 : 0;
 	data->index_table_expansion_addr_type =
 		nat4_params->index_table_expansion_addr_shared ? 1 : 0;
-	data->size_base_tables = nat4_params->size_base_tables;
-	data->size_expansion_tables = nat4_params->size_expansion_tables;
-	data->public_ip_addr = nat4_params->public_ip_addr;
+	data->size_base_tables = nat4_params->table_init.size_base_table;
+	data->size_expansion_tables =
+		nat4_params->table_init.size_expansion_table;
+	data->public_addr_info = nat4_params->public_addr_info;
+
+	return pyld;
+}
+
+static struct ipahal_imm_cmd_pyld *ipa_imm_cmd_construct_ip_v6_ct_init(
+	enum ipahal_imm_cmd_name cmd, const void *params, bool is_atomic_ctx)
+{
+	struct ipahal_imm_cmd_pyld *pyld;
+	struct ipa_imm_cmd_hw_ip_v6_ct_init *data;
+	struct ipahal_imm_cmd_ip_v6_ct_init *ipv6ct_params =
+		(struct ipahal_imm_cmd_ip_v6_ct_init *)params;
+
+	pyld = IPAHAL_MEM_ALLOC(sizeof(*pyld) + sizeof(*data), is_atomic_ctx);
+	if (unlikely(!pyld))
+		return pyld;
+	pyld->opcode = ipahal_imm_cmd_get_opcode(cmd);
+	pyld->len = sizeof(*data);
+	data = (struct ipa_imm_cmd_hw_ip_v6_ct_init *)pyld->data;
+
+	data->table_addr = ipv6ct_params->table_init.base_table_addr;
+	data->expansion_table_addr =
+		ipv6ct_params->table_init.expansion_table_addr;
+	data->table_index = ipv6ct_params->table_init.table_index;
+	data->table_addr_type =
+		ipv6ct_params->table_init.base_table_addr_shared ? 1 : 0;
+	data->expansion_table_addr_type =
+		ipv6ct_params->table_init.expansion_table_addr_shared ? 1 : 0;
+	data->size_base_table = ipv6ct_params->table_init.size_base_table;
+	data->size_expansion_table =
+		ipv6ct_params->table_init.size_expansion_table;
 
 	return pyld;
 }
@@ -685,6 +717,9 @@
 	[IPA_HW_v4_0][IPA_IMM_CMD_DMA_SHARED_MEM] = {
 		ipa_imm_cmd_construct_dma_shared_mem_v_4_0,
 		19},
+	[IPA_HW_v4_0][IPA_IMM_CMD_IP_V6_CT_INIT] = {
+		ipa_imm_cmd_construct_ip_v6_ct_init,
+		23}
 };
 
 /*
@@ -1526,13 +1561,21 @@
 	if (ipahal_hw_stats_init(ipa_hw_type)) {
 		IPAHAL_ERR("failed to init ipahal hw stats\n");
 		result = -EFAULT;
-		goto bail_free_ctx;
+		goto bail_free_fltrt;
+	}
+
+	if (ipahal_nat_init(ipa_hw_type)) {
+		IPAHAL_ERR("failed to init ipahal NAT\n");
+		result = -EFAULT;
+		goto bail_free_fltrt;
 	}
 
 	ipahal_debugfs_init();
 
 	return 0;
 
+bail_free_fltrt:
+	ipahal_fltrt_destroy();
 bail_free_ctx:
 	kfree(ipahal_ctx);
 	ipahal_ctx = NULL;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
index 56b884b..0c2697c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal.h
@@ -37,6 +37,7 @@
 	IPA_IMM_CMD_IP_PACKET_TAG_STATUS,
 	IPA_IMM_CMD_DMA_TASK_32B_ADDR,
 	IPA_IMM_CMD_TABLE_DMA,
+	IPA_IMM_CMD_IP_V6_CT_INIT,
 	IPA_IMM_CMD_MAX,
 };
 
@@ -46,19 +47,19 @@
  * struct ipahal_imm_cmd_ip_v4_filter_init - IP_V4_FILTER_INIT cmd payload
  * Inits IPv4 filter block.
  * @hash_rules_addr: Addr in sys mem where ipv4 hashable flt tbl starts
+ * @nhash_rules_addr: Addr in sys mem where ipv4 non-hashable flt tbl starts
  * @hash_rules_size: Size in bytes of the hashable tbl to cpy to local mem
  * @hash_local_addr: Addr in shared mem where ipv4 hashable flt tbl should
  *  be copied to
- * @nhash_rules_addr: Addr in sys mem where ipv4 non-hashable flt tbl starts
  * @nhash_rules_size: Size in bytes of the non-hashable tbl to cpy to local mem
  * @nhash_local_addr: Addr in shared mem where ipv4 non-hashable flt tbl should
  *  be copied to
  */
 struct ipahal_imm_cmd_ip_v4_filter_init {
 	u64 hash_rules_addr;
+	u64 nhash_rules_addr;
 	u32 hash_rules_size;
 	u32 hash_local_addr;
-	u64 nhash_rules_addr;
 	u32 nhash_rules_size;
 	u32 nhash_local_addr;
 };
@@ -67,79 +68,98 @@
  * struct ipahal_imm_cmd_ip_v6_filter_init - IP_V6_FILTER_INIT cmd payload
  * Inits IPv6 filter block.
  * @hash_rules_addr: Addr in sys mem where ipv6 hashable flt tbl starts
+ * @nhash_rules_addr: Addr in sys mem where ipv6 non-hashable flt tbl starts
  * @hash_rules_size: Size in bytes of the hashable tbl to cpy to local mem
  * @hash_local_addr: Addr in shared mem where ipv6 hashable flt tbl should
  *  be copied to
- * @nhash_rules_addr: Addr in sys mem where ipv6 non-hashable flt tbl starts
  * @nhash_rules_size: Size in bytes of the non-hashable tbl to cpy to local mem
  * @nhash_local_addr: Addr in shared mem where ipv6 non-hashable flt tbl should
  *  be copied to
  */
 struct ipahal_imm_cmd_ip_v6_filter_init {
 	u64 hash_rules_addr;
+	u64 nhash_rules_addr;
 	u32 hash_rules_size;
 	u32 hash_local_addr;
-	u64 nhash_rules_addr;
 	u32 nhash_rules_size;
 	u32 nhash_local_addr;
 };
 
 /*
+ * struct ipahal_imm_cmd_nat_ipv6ct_init_common - NAT/IPv6CT table init command
+ *                                                common part
+ * @base_table_addr: Address in sys/shared mem where base table start
+ * @expansion_table_addr: Address in sys/shared mem where expansion table
+ *  starts. Entries that result in hash collision are located in this table.
+ * @base_table_addr_shared: base_table_addr in shared mem (if not, then sys)
+ * @expansion_table_addr_shared: expansion_rules_addr in
+ *  shared mem (if not, then sys)
+ * @size_base_table: Num of entries in the base table
+ * @size_expansion_table: Num of entries in the expansion table
+ * @table_index: For future support of multiple tables
+ */
+struct ipahal_imm_cmd_nat_ipv6ct_init_common {
+	u64 base_table_addr;
+	u64 expansion_table_addr;
+	bool base_table_addr_shared;
+	bool expansion_table_addr_shared;
+	u16 size_base_table;
+	u16 size_expansion_table;
+	u8 table_index;
+};
+
+/*
  * struct ipahal_imm_cmd_ip_v4_nat_init - IP_V4_NAT_INIT cmd payload
  * Inits IPv4 NAT block. Initiate NAT table with it dimensions, location
- *  cache address abd itger related parameters.
- * @table_index: For future support of multiple NAT tables
- * @ipv4_rules_addr: Addr in sys/shared mem where ipv4 NAT rules start
- * @ipv4_rules_addr_shared: ipv4_rules_addr in shared mem (if not, then sys)
- * @ipv4_expansion_rules_addr: Addr in sys/shared mem where expantion NAT
- *  table starts. IPv4 NAT rules that result in NAT collision are located
- *  in this table.
- * @ipv4_expansion_rules_addr_shared: ipv4_expansion_rules_addr in
- *  shared mem (if not, then sys)
+ *  cache address and other related parameters.
+ * @table_init: table initialization parameters
  * @index_table_addr: Addr in sys/shared mem where index table, which points
  *  to NAT table starts
- * @index_table_addr_shared: index_table_addr in shared mem (if not, then sys)
  * @index_table_expansion_addr: Addr in sys/shared mem where expansion index
  *  table starts
+ * @index_table_addr_shared: index_table_addr in shared mem (if not, then sys)
  * @index_table_expansion_addr_shared: index_table_expansion_addr in
  *  shared mem (if not, then sys)
- * @size_base_tables: Num of entries in NAT tbl and idx tbl (each)
- * @size_expansion_tables: Num of entries in NAT expantion tbl and expantion
- *  idx tbl (each)
- * @public_ip_addr: public IP address
+ * @public_addr_info: Public IP addresses info suitable to the IPA H/W version
+ *                    IPA H/W >= 4.0 - PDN config table offset in SMEM
+ *                    IPA H/W < 4.0  - The public IP address
  */
 struct ipahal_imm_cmd_ip_v4_nat_init {
-	u8 table_index;
-	u64 ipv4_rules_addr;
-	bool ipv4_rules_addr_shared;
-	u64 ipv4_expansion_rules_addr;
-	bool ipv4_expansion_rules_addr_shared;
+	struct ipahal_imm_cmd_nat_ipv6ct_init_common table_init;
 	u64 index_table_addr;
-	bool index_table_addr_shared;
 	u64 index_table_expansion_addr;
+	bool index_table_addr_shared;
 	bool index_table_expansion_addr_shared;
-	u16 size_base_tables;
-	u16 size_expansion_tables;
-	u32 public_ip_addr;
+	u32 public_addr_info;
+};
+
+/*
+ * struct ipahal_imm_cmd_ip_v6_ct_init - IP_V6_CONN_TRACK_INIT cmd payload
+ * Inits IPv6CT block. Initiate IPv6CT table with it dimensions, location
+ *  cache address and other related parameters.
+ * @table_init: table initialization parameters
+ */
+struct ipahal_imm_cmd_ip_v6_ct_init {
+	struct ipahal_imm_cmd_nat_ipv6ct_init_common table_init;
 };
 
 /*
  * struct ipahal_imm_cmd_ip_v4_routing_init - IP_V4_ROUTING_INIT cmd payload
  * Inits IPv4 routing table/structure - with the rules and other related params
  * @hash_rules_addr: Addr in sys mem where ipv4 hashable rt tbl starts
+ * @nhash_rules_addr: Addr in sys mem where ipv4 non-hashable rt tbl starts
  * @hash_rules_size: Size in bytes of the hashable tbl to cpy to local mem
  * @hash_local_addr: Addr in shared mem where ipv4 hashable rt tbl should
  *  be copied to
- * @nhash_rules_addr: Addr in sys mem where ipv4 non-hashable rt tbl starts
  * @nhash_rules_size: Size in bytes of the non-hashable tbl to cpy to local mem
  * @nhash_local_addr: Addr in shared mem where ipv4 non-hashable rt tbl should
  *  be copied to
  */
 struct ipahal_imm_cmd_ip_v4_routing_init {
 	u64 hash_rules_addr;
+	u64 nhash_rules_addr;
 	u32 hash_rules_size;
 	u32 hash_local_addr;
-	u64 nhash_rules_addr;
 	u32 nhash_rules_size;
 	u32 nhash_local_addr;
 };
@@ -148,19 +168,19 @@
  * struct ipahal_imm_cmd_ip_v6_routing_init - IP_V6_ROUTING_INIT cmd payload
  * Inits IPv6 routing table/structure - with the rules and other related params
  * @hash_rules_addr: Addr in sys mem where ipv6 hashable rt tbl starts
+ * @nhash_rules_addr: Addr in sys mem where ipv6 non-hashable rt tbl starts
  * @hash_rules_size: Size in bytes of the hashable tbl to cpy to local mem
  * @hash_local_addr: Addr in shared mem where ipv6 hashable rt tbl should
  *  be copied to
- * @nhash_rules_addr: Addr in sys mem where ipv6 non-hashable rt tbl starts
  * @nhash_rules_size: Size in bytes of the non-hashable tbl to cpy to local mem
  * @nhash_local_addr: Addr in shared mem where ipv6 non-hashable rt tbl should
  *  be copied to
  */
 struct ipahal_imm_cmd_ip_v6_routing_init {
 	u64 hash_rules_addr;
+	u64 nhash_rules_addr;
 	u32 hash_rules_size;
 	u32 hash_local_addr;
-	u64 nhash_rules_addr;
 	u32 nhash_rules_size;
 	u32 nhash_local_addr;
 };
@@ -189,36 +209,20 @@
 };
 
 /*
- * struct ipahal_imm_cmd_nat_dma - NAT_DMA cmd payload
- * Perform DMA operation on NAT related mem addressess. Copy data into
- *  different locations within NAT associated tbls. (For add/remove NAT rules)
- * @table_index: NAT tbl index. Defines the NAT tbl on which to perform DMA op.
- * @base_addr: Base addr to which the DMA operation should be performed.
- * @offset: offset in bytes from base addr to write 'data' to
- * @data: data to be written
- */
-struct ipahal_imm_cmd_nat_dma {
-	u8 table_index;
-	u8 base_addr;
-	u32 offset;
-	u16 data;
-};
-
-/*
  * struct ipahal_imm_cmd_table_dma - TABLE_DMA cmd payload
  * Perform DMA operation on NAT and IPV6 connection tracking related mem
- * addresses. Copy data into different locations within IPV6CT and NAT
+ * addresses. Copy data into different locations within IPv6CT and NAT
  * associated tbls. (For add/remove NAT rules)
- * @table_index: NAT tbl index. Defines the tbl on which to perform DMA op.
- * @base_addr: Base addr to which the DMA operation should be performed.
  * @offset: offset in bytes from base addr to write 'data' to
  * @data: data to be written
+ * @table_index: NAT tbl index. Defines the tbl on which to perform DMA op.
+ * @base_addr: Base addr to which the DMA operation should be performed.
  */
 struct ipahal_imm_cmd_table_dma {
-	u8 table_index;
-	u8 base_addr;
 	u32 offset;
 	u16 data;
+	u8 table_index;
+	u8 base_addr;
 };
 
 /*
@@ -275,6 +279,7 @@
 /*
  * struct ipahal_imm_cmd_dma_shared_mem - DMA_SHARED_MEM cmd payload
  * Perform mem copy into or out of the SW area of IPA local mem
+ * @system_addr: Address in system memory
  * @size: Size in bytes of data to copy. Expected size is up to 2K bytes
  * @local_addr: Address in IPA local memory
  * @clear_after_read: Clear local memory at the end of a read operation allows
@@ -282,16 +287,15 @@
  * @is_read: Read operation from local memory? If not, then write.
  * @skip_pipeline_clear: if to skip pipeline clear waiting (don't wait)
  * @pipeline_clear_option: options for pipeline clear waiting
- * @system_addr: Address in system memory
  */
 struct ipahal_imm_cmd_dma_shared_mem {
+	u64 system_addr;
 	u32 size;
 	u32 local_addr;
 	bool clear_after_read;
 	bool is_read;
 	bool skip_pipeline_clear;
 	enum ipahal_pipeline_clear_option pipeline_clear_options;
-	u64 system_addr;
 };
 
 /*
@@ -515,6 +519,7 @@
  *   following statuses: IPA_STATUS_PACKET, IPA_STATUS_DROPPED_PACKET,
  *   IPA_STATUS_SUSPENDED_PACKET.
  *  Other statuses types has different status packet structure.
+ * @tag_info: S/W defined value provided via immediate command
  * @status_opcode: The Type of the status (Opcode).
  * @exception: The first exception that took place.
  *  In case of exception, src endp and pkt len are always valid.
@@ -522,9 +527,6 @@
  *  and processing it may passed at IPA. See enum ipahal_pkt_status_mask
  * @pkt_len: Pkt pyld len including hdr and retained hdr if used. Does
  *  not include padding or checksum trailer len.
- * @endp_src_idx: Source end point index.
- * @endp_dest_idx: Destination end point index.
- *  Not valid in case of exception
  * @metadata: meta data value used by packet
  * @flt_local: Filter table location flag: Does matching flt rule belongs to
  *  flt tbl that resides in lcl memory? (if not, then system mem)
@@ -535,57 +537,59 @@
  *  specifies to retain header?
  * @flt_miss: Filtering miss flag: Was their a filtering rule miss?
  *   In case of miss, all flt info to be ignored
- * @flt_rule_id: The ID of the matching filter rule (if no miss).
- *  This info can be combined with endp_src_idx to locate the exact rule.
  * @rt_local: Route table location flag: Does matching rt rule belongs to
  *  rt tbl that resides in lcl memory? (if not, then system mem)
  * @rt_hash: Route hash hit flag: Does matching rt rule was in hash tbl?
  * @ucp: UC Processing flag
- * @rt_tbl_idx: Index of rt tbl that contains the rule on which was a match
  * @rt_miss: Routing miss flag: Was their a routing rule miss?
- * @rt_rule_id: The ID of the matching rt rule. (if no miss). This info
- *  can be combined with rt_tbl_idx to locate the exact rule.
  * @nat_hit: NAT hit flag: Was their NAT hit?
- * @nat_entry_idx: Index of the NAT entry used of NAT processing
  * @nat_type: Defines the type of the NAT operation:
- * @tag_info: S/W defined value provided via immediate command
- * @seq_num: Per source endp unique packet sequence number
  * @time_of_day_ctr: running counter from IPA clock
  * @hdr_local: Header table location flag: In header insertion, was the header
  *  taken from the table resides in local memory? (If no, then system mem)
- * @hdr_offset: Offset of used header in the header table
  * @frag_hit: Frag hit flag: Was their frag rule hit in H/W frag table?
+ * @flt_rule_id: The ID of the matching filter rule (if no miss).
+ *  This info can be combined with endp_src_idx to locate the exact rule.
+ * @rt_rule_id: The ID of the matching rt rule. (if no miss). This info
+ *  can be combined with rt_tbl_idx to locate the exact rule.
+ * @nat_entry_idx: Index of the NAT entry used of NAT processing
+ * @hdr_offset: Offset of used header in the header table
+ * @endp_src_idx: Source end point index.
+ * @endp_dest_idx: Destination end point index.
+ *  Not valid in case of exception
+ * @rt_tbl_idx: Index of rt tbl that contains the rule on which was a match
+ * @seq_num: Per source endp unique packet sequence number
  * @frag_rule: Frag rule index in H/W frag table in case of frag hit
  */
 struct ipahal_pkt_status {
+	u64 tag_info;
 	enum ipahal_pkt_status_opcode status_opcode;
 	enum ipahal_pkt_status_exception exception;
 	u32 status_mask;
 	u32 pkt_len;
-	u8 endp_src_idx;
-	u8 endp_dest_idx;
 	u32 metadata;
 	bool flt_local;
 	bool flt_hash;
 	bool flt_global;
 	bool flt_ret_hdr;
 	bool flt_miss;
-	u16 flt_rule_id;
 	bool rt_local;
 	bool rt_hash;
 	bool ucp;
-	u8 rt_tbl_idx;
 	bool rt_miss;
-	u16 rt_rule_id;
 	bool nat_hit;
-	u16 nat_entry_idx;
 	enum ipahal_pkt_status_nat_type nat_type;
-	u64 tag_info;
-	u8 seq_num;
 	u32 time_of_day_ctr;
 	bool hdr_local;
-	u16 hdr_offset;
 	bool frag_hit;
+	u16 flt_rule_id;
+	u16 rt_rule_id;
+	u16 nat_entry_idx;
+	u16 hdr_offset;
+	u8 endp_src_idx;
+	u8 endp_dest_idx;
+	u8 rt_tbl_idx;
+	u8 seq_num;
 	u8 frag_rule;
 };
 
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
index 5eb1aef..4ccb7e0 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_i.h
@@ -125,10 +125,10 @@
  * struct ipa_imm_cmd_hw_ip_v4_nat_init - IP_V4_NAT_INIT command payload
  *  in H/W format.
  * Inits IPv4 NAT block. Initiate NAT table with it dimensions, location
- *  cache address abd itger related parameters.
+ *  cache address and other related parameters.
  * @ipv4_rules_addr: Addr in sys/shared mem where ipv4 NAT rules start
- * @ipv4_expansion_rules_addr: Addr in sys/shared mem where expantion NAT
- *  table starts. IPv4 NAT rules that result in NAT collision are located
+ * @ipv4_expansion_rules_addr: Addr in sys/shared mem where expansion NAT
+ *  table starts. IPv4 NAT rules that result in hash collision are located
  *  in this table.
  * @index_table_addr: Addr in sys/shared mem where index table, which points
  *  to NAT table starts
@@ -143,11 +143,12 @@
  * @index_table_expansion_addr_type: index_table_expansion_addr in
  *  sys or shared mem
  * @size_base_tables: Num of entries in NAT tbl and idx tbl (each)
- * @size_expansion_tables: Num of entries in NAT expantion tbl and expantion
+ * @size_expansion_tables: Num of entries in NAT expansion tbl and expansion
  *  idx tbl (each)
  * @rsvd2: reserved
- * @public_ip_addr: public IP address. for IPAv4 this is the PDN config table
- *  offset in SMEM
+ * @public_addr_info: Public IP addresses info suitable to the IPA H/W version
+ *                    IPA H/W >= 4.0 - PDN config table offset in SMEM
+ *                    IPA H/W < 4.0  - The public IP address
  */
 struct ipa_imm_cmd_hw_ip_v4_nat_init {
 	u64 ipv4_rules_addr:64;
@@ -163,7 +164,38 @@
 	u64 size_base_tables:12;
 	u64 size_expansion_tables:10;
 	u64 rsvd2:2;
-	u64 public_ip_addr:32;
+	u64 public_addr_info:32;
+};
+
+/*
+ * struct ipa_imm_cmd_hw_ip_v6_ct_init - IP_V6_CONN_TRACK_INIT command payload
+ *  in H/W format.
+ * Inits IPv6CT block. Initiate IPv6CT table with it dimensions, location
+ *  cache address and other related parameters.
+ * @table_addr: Address in sys/shared mem where IPv6CT rules start
+ * @expansion_table_addr: Address in sys/shared mem where IPv6CT expansion
+ *  table starts. IPv6CT rules that result in hash collision are located
+ *  in this table.
+ * @table_index: For future support of multiple IPv6CT tables
+ * @rsvd1: reserved
+ * @table_addr_type: table_addr in sys or shared mem
+ * @expansion_table_addr_type: expansion_table_addr in sys or shared mem
+ * @rsvd2: reserved
+ * @size_base_tables: Number of entries in IPv6CT table
+ * @size_expansion_tables: Number of entries in IPv6CT expansion table
+ * @rsvd3: reserved
+ */
+struct ipa_imm_cmd_hw_ip_v6_ct_init {
+	u64 table_addr:64;
+	u64 expansion_table_addr:64;
+	u64 table_index:3;
+	u64 rsvd1:1;
+	u64 table_addr_type:1;
+	u64 expansion_table_addr_type:1;
+	u64 rsvd2:2;
+	u64 size_base_table:12;
+	u64 size_expansion_table:10;
+	u64 rsvd3:34;
 };
 
 /*
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.c
new file mode 100644
index 0000000..d335ba6
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.c
@@ -0,0 +1,360 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/debugfs.h>
+#include "ipahal_nat.h"
+#include "ipahal_nat_i.h"
+#include "ipahal_i.h"
+
+#define IPA_64_LOW_32_MASK (0xFFFFFFFF)
+#define IPA_64_HIGH_32_MASK (0xFFFFFFFF00000000ULL)
+
+static const char *ipahal_nat_type_to_str[IPA_NAT_MAX] = {
+	__stringify(IPAHAL_NAT_IPV4),
+	__stringify(IPAHAL_NAT_IPV4_INDEX),
+	__stringify(IPAHAL_NAT_IPV4_PDN),
+	__stringify(IPAHAL_NAT_IPV6CT)
+};
+
+static size_t ipa_nat_ipv4_entry_size_v_3_0(void)
+{
+	return sizeof(struct ipa_nat_hw_ipv4_entry);
+}
+
+static size_t ipa_nat_ipv4_index_entry_size_v_3_0(void)
+{
+	return sizeof(struct ipa_nat_hw_indx_entry);
+}
+
+static size_t ipa_nat_ipv4_pdn_entry_size_v_4_0(void)
+{
+	return sizeof(struct ipa_nat_hw_pdn_entry);
+}
+
+static size_t ipa_nat_ipv6ct_entry_size_v_4_0(void)
+{
+	return sizeof(struct ipa_nat_hw_ipv6ct_entry);
+}
+
+static bool ipa_nat_ipv4_is_entry_zeroed_v_3_0(const void *entry)
+{
+	struct ipa_nat_hw_ipv4_entry zero_entry = { 0 };
+
+	return (memcmp(&zero_entry, entry, sizeof(zero_entry))) ? false : true;
+}
+
+static bool ipa_nat_ipv4_is_index_entry_zeroed_v_3_0(const void *entry)
+{
+	struct ipa_nat_hw_indx_entry zero_entry = { 0 };
+
+	return (memcmp(&zero_entry, entry, sizeof(zero_entry))) ? false : true;
+}
+
+static bool ipa_nat_ipv4_is_pdn_entry_zeroed_v_4_0(const void *entry)
+{
+	struct ipa_nat_hw_pdn_entry zero_entry = { 0 };
+
+	return (memcmp(&zero_entry, entry, sizeof(zero_entry))) ? false : true;
+}
+
+static bool ipa_nat_ipv6ct_is_entry_zeroed_v_4_0(const void *entry)
+{
+	struct ipa_nat_hw_ipv6ct_entry zero_entry = { 0 };
+
+	return (memcmp(&zero_entry, entry, sizeof(zero_entry))) ? false : true;
+}
+
+static int ipa_nat_ipv4_stringify_entry_v_3_0(const void *entry,
+	char *buff, size_t buff_size)
+{
+	const struct ipa_nat_hw_ipv4_entry *nat_entry =
+		(const struct ipa_nat_hw_ipv4_entry *)entry;
+
+	return scnprintf(buff, buff_size,
+		"\t\tPrivate_IP=%pI4h  Target_IP=%pI4h\n"
+		"\t\tNext_Index=%d  Public_Port=%d\n"
+		"\t\tPrivate_Port=%d  Target_Port=%d\n"
+		"\t\tIP_CKSM_delta=0x%x  Enable=%s  Redirect=%s\n"
+		"\t\tTime_stamp=0x%x Proto=%d\n"
+		"\t\tPrev_Index=%d  Indx_tbl_entry=%d\n"
+		"\t\tTCP_UDP_cksum_delta=0x%x\n",
+		&nat_entry->private_ip, &nat_entry->target_ip,
+		nat_entry->next_index, nat_entry->public_port,
+		nat_entry->private_port, nat_entry->target_port,
+		nat_entry->ip_chksum,
+		(nat_entry->enable) ? "true" : "false",
+		(nat_entry->redirect) ? "Direct_To_APPS" : "Fwd_to_route",
+		nat_entry->time_stamp, nat_entry->protocol,
+		nat_entry->prev_index, nat_entry->indx_tbl_entry,
+		nat_entry->tcp_udp_chksum);
+}
+
+static int ipa_nat_ipv4_stringify_entry_v_4_0(const void *entry,
+	char *buff, size_t buff_size)
+{
+	int length;
+	const struct ipa_nat_hw_ipv4_entry *nat_entry =
+		(const struct ipa_nat_hw_ipv4_entry *)entry;
+
+	length = ipa_nat_ipv4_stringify_entry_v_3_0(entry, buff, buff_size);
+
+	length += scnprintf(buff + length, buff_size - length,
+		"\t\tPDN_Index=%d\n", nat_entry->pdn_index);
+
+	return length;
+}
+
+static int ipa_nat_ipv4_index_stringify_entry_v_3_0(const void *entry,
+	char *buff, size_t buff_size)
+{
+	const struct ipa_nat_hw_indx_entry *index_entry =
+		(const struct ipa_nat_hw_indx_entry *)entry;
+
+	return scnprintf(buff, buff_size,
+		"\t\tTable_Entry=%d  Next_Index=%d\n",
+		index_entry->tbl_entry, index_entry->next_index);
+}
+
+static int ipa_nat_ipv4_pdn_stringify_entry_v_4_0(const void *entry,
+	char *buff, size_t buff_size)
+{
+	const struct ipa_nat_hw_pdn_entry *pdn_entry =
+		(const struct ipa_nat_hw_pdn_entry *)entry;
+
+	return scnprintf(buff, buff_size,
+		"ip=%pI4h src_metadata=0x%X, dst_metadata=0x%X\n",
+		&pdn_entry->public_ip,
+		pdn_entry->src_metadata, pdn_entry->dst_metadata);
+}
+
+static inline int ipa_nat_ipv6_stringify_addr(char *buff, size_t buff_size,
+	const char *msg, u64 lsb, u64 msb)
+{
+	struct in6_addr addr;
+
+	addr.s6_addr32[0] = cpu_to_be32((msb & IPA_64_HIGH_32_MASK) >> 32);
+	addr.s6_addr32[1] = cpu_to_be32(msb & IPA_64_LOW_32_MASK);
+	addr.s6_addr32[2] = cpu_to_be32((lsb & IPA_64_HIGH_32_MASK) >> 32);
+	addr.s6_addr32[3] = cpu_to_be32(lsb & IPA_64_LOW_32_MASK);
+
+	return scnprintf(buff, buff_size,
+		"\t\t%s_IPv6_Addr=%pI6c\n", msg, &addr);
+}
+
+static int ipa_nat_ipv6ct_stringify_entry_v_4_0(const void *entry,
+	char *buff, size_t buff_size)
+{
+	int length = 0;
+	const struct ipa_nat_hw_ipv6ct_entry *ipv6ct_entry =
+		(const struct ipa_nat_hw_ipv6ct_entry *)entry;
+
+	length += ipa_nat_ipv6_stringify_addr(
+		buff + length,
+		buff_size - length,
+		"Src",
+		ipv6ct_entry->src_ipv6_lsb,
+		ipv6ct_entry->src_ipv6_msb);
+
+	length += ipa_nat_ipv6_stringify_addr(
+		buff + length,
+		buff_size - length,
+		"Dest",
+		ipv6ct_entry->dest_ipv6_lsb,
+		ipv6ct_entry->dest_ipv6_msb);
+
+	length += scnprintf(buff + length, buff_size - length,
+		"\t\tEnable=%s Redirect=%s Time_Stamp=0x%x Proto=%d\n"
+		"\t\tNext_Index=%d Dest_Port=%d Src_Port=%d\n"
+		"\t\tDirection Settings: Out=%s In=%s\n"
+		"\t\tPrev_Index=%d\n",
+		(ipv6ct_entry->enable) ? "true" : "false",
+		(ipv6ct_entry->redirect) ? "Direct_To_APPS" : "Fwd_to_route",
+		ipv6ct_entry->time_stamp,
+		ipv6ct_entry->protocol,
+		ipv6ct_entry->next_index,
+		ipv6ct_entry->dest_port,
+		ipv6ct_entry->src_port,
+		(ipv6ct_entry->out_allowed) ? "Allow" : "Deny",
+		(ipv6ct_entry->in_allowed) ? "Allow" : "Deny",
+		ipv6ct_entry->prev_index);
+
+	return length;
+}
+
+/*
+ * struct ipahal_nat_obj - H/W information for specific IPA version
+ * @entry_size - CB to get the size of the entry
+ * @is_entry_zeroed - CB to determine whether an entry is definitely zero
+ * @stringify_entry - CB to create string that represents an entry
+ */
+struct ipahal_nat_obj {
+	size_t (*entry_size)(void);
+	bool (*is_entry_zeroed)(const void *entry);
+	int (*stringify_entry)(const void *entry, char *buff, size_t buff_size);
+};
+
+/*
+ * This table contains the info regard each NAT type for IPAv3 and later.
+ * Information like: get entry size and stringify entry functions.
+ * All the information on all the NAT types on IPAv3 are statically
+ * defined below. If information is missing regard some NAT type on some
+ * IPA version, the init function will fill it with the information from the
+ * previous IPA version.
+ * Information is considered missing if all of the fields are 0
+ */
+static struct ipahal_nat_obj ipahal_nat_objs[IPA_HW_MAX][IPA_NAT_MAX] = {
+	/* IPAv3 */
+	[IPA_HW_v3_0][IPAHAL_NAT_IPV4] = {
+			ipa_nat_ipv4_entry_size_v_3_0,
+			ipa_nat_ipv4_is_entry_zeroed_v_3_0,
+			ipa_nat_ipv4_stringify_entry_v_3_0
+		},
+	[IPA_HW_v3_0][IPAHAL_NAT_IPV4_INDEX] = {
+			ipa_nat_ipv4_index_entry_size_v_3_0,
+			ipa_nat_ipv4_is_index_entry_zeroed_v_3_0,
+			ipa_nat_ipv4_index_stringify_entry_v_3_0
+		},
+
+	/* IPAv4 */
+	[IPA_HW_v4_0][IPAHAL_NAT_IPV4] = {
+			ipa_nat_ipv4_entry_size_v_3_0,
+			ipa_nat_ipv4_is_entry_zeroed_v_3_0,
+			ipa_nat_ipv4_stringify_entry_v_4_0
+		},
+	[IPA_HW_v4_0][IPAHAL_NAT_IPV4_PDN] = {
+			ipa_nat_ipv4_pdn_entry_size_v_4_0,
+			ipa_nat_ipv4_is_pdn_entry_zeroed_v_4_0,
+			ipa_nat_ipv4_pdn_stringify_entry_v_4_0
+		},
+	[IPA_HW_v4_0][IPAHAL_NAT_IPV6CT] = {
+			ipa_nat_ipv6ct_entry_size_v_4_0,
+			ipa_nat_ipv6ct_is_entry_zeroed_v_4_0,
+			ipa_nat_ipv6ct_stringify_entry_v_4_0
+		}
+};
+
+static void ipahal_nat_check_obj(struct ipahal_nat_obj *obj,
+	int nat_type, int ver)
+{
+	WARN(obj->entry_size == NULL, "%s missing entry_size for version %d\n",
+		ipahal_nat_type_str(nat_type), ver);
+	WARN(obj->is_entry_zeroed == NULL,
+		"%s missing is_entry_zeroed for version %d\n",
+		ipahal_nat_type_str(nat_type), ver);
+	WARN(obj->stringify_entry == NULL,
+		"%s missing stringify_entry for version %d\n",
+		ipahal_nat_type_str(nat_type), ver);
+}
+
+/*
+ * ipahal_nat_init() - Build the NAT information table
+ *  See ipahal_nat_objs[][] comments
+ */
+int ipahal_nat_init(enum ipa_hw_type ipa_hw_type)
+{
+	int i;
+	int j;
+	struct ipahal_nat_obj zero_obj, *next_obj;
+
+	IPAHAL_DBG("Entry - HW_TYPE=%d\n", ipa_hw_type);
+
+	memset(&zero_obj, 0, sizeof(zero_obj));
+
+	if ((ipa_hw_type < 0) || (ipa_hw_type >= IPA_HW_MAX)) {
+		IPAHAL_ERR("invalid IPA HW type (%d)\n", ipa_hw_type);
+		return -EINVAL;
+	}
+
+	for (i = IPA_HW_v3_0 ; i < ipa_hw_type ; ++i) {
+		for (j = 0; j < IPA_NAT_MAX; ++j) {
+			next_obj = &ipahal_nat_objs[i + 1][j];
+			if (!memcmp(next_obj, &zero_obj, sizeof(*next_obj))) {
+				memcpy(next_obj, &ipahal_nat_objs[i][j],
+					sizeof(*next_obj));
+			} else {
+				ipahal_nat_check_obj(next_obj, j, i + 1);
+			}
+		}
+	}
+
+	return 0;
+}
+
+const char *ipahal_nat_type_str(enum ipahal_nat_type nat_type)
+{
+	if (nat_type < 0 || nat_type >= IPA_NAT_MAX) {
+		IPAHAL_ERR("requested NAT type %d is invalid\n", nat_type);
+		return "Invalid NAT type";
+	}
+
+	return ipahal_nat_type_to_str[nat_type];
+}
+
+int ipahal_nat_entry_size(enum ipahal_nat_type nat_type, size_t *entry_size)
+{
+	if (WARN(entry_size == NULL, "entry_size is NULL\n"))
+		return -EINVAL;
+	if (WARN(nat_type < 0 || nat_type >= IPA_NAT_MAX,
+		"requested NAT type %d is invalid\n", nat_type))
+		return -EINVAL;
+
+	IPAHAL_DBG("Get the entry size for NAT type=%s\n",
+		ipahal_nat_type_str(nat_type));
+	*entry_size = ipahal_nat_objs[ipahal_ctx->hw_type][nat_type].
+		entry_size();
+	IPAHAL_DBG("The entry size is %zu\n", *entry_size);
+
+	return 0;
+}
+
+int ipahal_nat_is_entry_zeroed(enum ipahal_nat_type nat_type, void *entry,
+	bool *entry_zeroed)
+{
+	if (WARN(entry == NULL || entry_zeroed == NULL,
+		"NULL pointer received\n"))
+		return -EINVAL;
+	if (WARN(nat_type < 0 || nat_type >= IPA_NAT_MAX,
+		"requested NAT type %d is invalid\n", nat_type))
+		return -EINVAL;
+
+	IPAHAL_DBG("Determine whether the entry is zeroed for NAT type=%s\n",
+		ipahal_nat_type_str(nat_type));
+	*entry_zeroed = ipahal_nat_objs[ipahal_ctx->hw_type][nat_type].
+		is_entry_zeroed(entry);
+	IPAHAL_DBG("The entry is %szeroed\n", (*entry_zeroed) ? "" : "not ");
+
+	return 0;
+}
+
+int ipahal_nat_stringify_entry(enum ipahal_nat_type nat_type, void *entry,
+	char *buff, size_t buff_size)
+{
+	int result;
+
+	if (WARN(entry == NULL || buff == NULL, "NULL pointer received\n"))
+		return -EINVAL;
+	if (WARN(!buff_size, "The output buff size is zero\n"))
+		return -EINVAL;
+	if (WARN(nat_type < 0 || nat_type >= IPA_NAT_MAX,
+		"requested NAT type %d is invalid\n", nat_type))
+		return -EINVAL;
+
+	IPAHAL_DBG("Create the string for the entry of NAT type=%s\n",
+		ipahal_nat_type_str(nat_type));
+	result = ipahal_nat_objs[ipahal_ctx->hw_type][nat_type].
+		stringify_entry(entry, buff, buff_size);
+	IPAHAL_DBG("The string successfully created with length %d\n",
+		result);
+
+	return result;
+}
+
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.h
new file mode 100644
index 0000000..f99c1a0
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.h
@@ -0,0 +1,67 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IPAHAL_NAT_H_
+#define _IPAHAL_NAT_H_
+
+/*
+ * NAT types
+ *
+ * NOTE:: Any change to this enum, need to change to ipahal_nat_to_str
+ *	  array as well.
+ */
+enum ipahal_nat_type {
+	IPAHAL_NAT_IPV4,
+	IPAHAL_NAT_IPV4_INDEX,
+	IPAHAL_NAT_IPV4_PDN,
+	IPAHAL_NAT_IPV6CT,
+	IPA_NAT_MAX
+};
+
+/* NAT Function APIs */
+
+/*
+ * ipahal_nat_type_str() - returns string that represent the NAT type
+ * @nat_type: [in] NAT type
+ */
+const char *ipahal_nat_type_str(enum ipahal_nat_type nat_type);
+
+/*
+ * ipahal_nat_entry_size() - Gets the size of HW NAT entry
+ * @nat_type: [in] The type of the NAT entry
+ * @entry_size: [out] The size of the HW NAT entry
+ */
+int ipahal_nat_entry_size(enum ipahal_nat_type nat_type, size_t *entry_size);
+
+/*
+ * ipahal_nat_is_entry_zeroed() - Determines whether HW NAT entry is
+ *                                definitely zero
+ * @nat_type: [in] The type of the NAT entry
+ * @entry: [in] The NAT entry
+ * @entry_zeroed: [out] True if the received entry is definitely zero
+ */
+int ipahal_nat_is_entry_zeroed(enum ipahal_nat_type nat_type, void *entry,
+	bool *entry_zeroed);
+
+/*
+ * ipahal_nat_stringify_entry() - Creates a string for HW NAT entry
+ * @nat_type: [in] The type of the NAT entry
+ * @entry: [in] The NAT entry
+ * @buff: [out] Output buffer for the result string
+ * @buff_size: [in] The size of the output buffer
+ * @return the number of characters written into buff not including
+ *         the trailing '\0'
+ */
+int ipahal_nat_stringify_entry(enum ipahal_nat_type nat_type, void *entry,
+	char *buff, size_t buff_size);
+
+#endif /* _IPAHAL_NAT_H_ */
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat_i.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat_i.h
new file mode 100644
index 0000000..83bd0f5
--- /dev/null
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat_i.h
@@ -0,0 +1,153 @@
+/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _IPAHAL_NAT_I_H_
+#define _IPAHAL_NAT_I_H_
+
+#include <linux/msm_ipa.h>
+
+/* ----------------------- IPv4 NAT Table Entry  -------------------------
+ *
+ * -----------------------------------------------------------------------
+ * |  7  |     6    |   5    |   4   |    3        | 2 |    1    |    0  |
+ * -----------------------------------------------------------------------
+ * |           Target IP(4B)         |             Private IP(4B)        |
+ * -----------------------------------------------------------------------
+ * |Target Port(2B) |Private Port(2B)| Public Port(2B) | Next Index(2B)  |
+ * -----------------------------------------------------------------------
+ * |Proto|      TimeStamp(3B)        |     Flags(2B)   |IP check sum Diff|
+ * |(1B) |                           |EN|Redirect|Resv |        (2B)     |
+ * -----------------------------------------------------------------------
+ * |TCP/UDP checksum|  PDN info(2B)  |    SW Specific Parameters(4B)     |
+ * |    diff (2B)   |Info|Resv       |index table entry|  prev index     |
+ * -----------------------------------------------------------------------
+ */
+struct ipa_nat_hw_ipv4_entry {
+	/* An IP address can't be bit-field, because its address is used */
+	u32 private_ip;
+	u32 target_ip;
+
+	u32 next_index : 16;
+	u32 public_port : 16;
+	u32 private_port : 16;
+	u32 target_port : 16;
+	u32 ip_chksum : 16;
+
+	u32 rsvd1 : 14;
+	u32 redirect : 1;
+	u32 enable : 1;
+
+	u32 time_stamp : 24;
+	u32 protocol : 8;
+
+	u32 prev_index : 16;
+	u32 indx_tbl_entry : 16;
+
+	u32 rsvd2 : 12;
+	u32 pdn_index : 4; /* IPA 4.0 and greater */
+
+	u32 tcp_udp_chksum : 16;
+};
+
+/*--- IPV4 NAT Index Table Entry --
+ *---------------------------------
+ *|   3   |   2   |   1   |   0   |
+ *---------------------------------
+ *|next index(2B) |table entry(2B)|
+ *---------------------------------
+ */
+struct ipa_nat_hw_indx_entry {
+	u16 tbl_entry;
+	u16 next_index;
+};
+
+/**
+ * struct ipa_nat_hw_pdn_entry - IPA PDN config table entry
+ * @public_ip: the PDN's public ip
+ * @src_metadata: the PDN's metadata to be replaced for source NAT
+ * @dst_metadata: the PDN's metadata to be replaced for destination NAT
+ * @resrvd: reserved field
+ * ---------------------------------
+ * |   3   |   2   |   1   |   0   |
+ * ---------------------------------
+ * |        public_ip (4B)         |
+ * ---------------------------------
+ * |      src_metadata (4B)        |
+ * ---------------------------------
+ * |      dst_metadata (4B)        |
+ * ---------------------------------
+ * |         resrvd (4B)           |
+ * ---------------------------------
+ */
+struct ipa_nat_hw_pdn_entry {
+	u32 public_ip;
+	u32 src_metadata;
+	u32 dst_metadata;
+	u32 resrvd;
+};
+
+/*-------------------------  IPV6CT Table Entry  ------------------------------
+ *-----------------------------------------------------------------------------
+ *|   7    |      6      |  5  |  4   |        3         |  2  |   1  |   0   |
+ *-----------------------------------------------------------------------------
+ *|                   Outbound Src IPv6 Address (8 LSB Bytes)                 |
+ *-----------------------------------------------------------------------------
+ *|                   Outbound Src IPv6 Address (8 MSB Bytes)                 |
+ *-----------------------------------------------------------------------------
+ *|                   Outbound Dest IPv6 Address (8 LSB Bytes)                |
+ *-----------------------------------------------------------------------------
+ *|                   Outbound Dest IPv6 Address (8 MSB Bytes)                |
+ *-----------------------------------------------------------------------------
+ *|Protocol|      TimeStamp (3B)      |       Flags (2B)       |Reserved (2B) |
+ *|  (1B)  |                          |Enable|Redirect|Resv    |              |
+ *-----------------------------------------------------------------------------
+ *|Reserved|Direction(1B)|Src Port(2B)|     Dest Port (2B)     |Next Index(2B)|
+ *|  (1B)  |IN|OUT|Resv  |            |                        |              |
+ *-----------------------------------------------------------------------------
+ *|    SW Specific Parameters(4B)     |                Reserved (4B)          |
+ *|    Prev Index (2B)   |Reserved(2B)|                                       |
+ *-----------------------------------------------------------------------------
+ *|                            Reserved (8B)                                  |
+ *-----------------------------------------------------------------------------
+ */
+struct ipa_nat_hw_ipv6ct_entry {
+	/* An IP address can't be bit-field, because its address is used */
+	u64 src_ipv6_lsb;
+	u64 src_ipv6_msb;
+	u64 dest_ipv6_lsb;
+	u64 dest_ipv6_msb;
+
+	u64 rsvd1 : 30;
+	u64 redirect : 1;
+	u64 enable : 1;
+
+	u64 time_stamp : 24;
+	u64 protocol : 8;
+
+	u64 next_index : 16;
+	u64 dest_port : 16;
+	u64 src_port : 16;
+	u64 rsvd2 : 6;
+	u64 out_allowed : 1;
+	u64 in_allowed : 1;
+	u64 rsvd3 : 8;
+
+	u64 rsvd4 : 48;
+	u64 prev_index : 16;
+
+	u64 rsvd5 : 64;
+};
+
+int ipahal_nat_init(enum ipa_hw_type ipa_hw_type);
+
+#endif /* _IPAHAL_NAT_I_H_ */
+