Merge "msm: ipa3: Ignore invalid NAT entries when counting nat rules"
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
index e88ab27..07773eb 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2012-2018, 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
@@ -1517,6 +1517,7 @@
 	char *entry;
 	size_t entry_size;
 	bool entry_zeroed;
+	bool entry_valid;
 	u32 i, num_entries = 0, id = *rule_id, pos = 0;
 
 	IPADBG("\n");
@@ -1538,20 +1539,33 @@
 			&entry_zeroed);
 		if (result) {
 			IPAERR(
-				"Failed to determine whether the %s entry is definitely zero",
-				ipahal_nat_type_str(nat_type));
+				"Failed to determine whether the %s entry is definitely zero\n"
+					, ipahal_nat_type_str(nat_type));
 			goto bail;
 		}
 		if (entry_zeroed)
 			continue;
 
-		pos += scnprintf(buff + pos, buff_size - pos,
-			"\tEntry_Index=%d\n", id);
+		result = ipahal_nat_is_entry_valid(nat_type, entry,
+			&entry_valid);
+		if (result) {
+			IPAERR(
+				"Failed to determine whether the %s entry is valid\n"
+					, ipahal_nat_type_str(nat_type));
+			goto bail;
+		}
+
+		if (entry_valid) {
+			++num_entries;
+			pos += scnprintf(buff + pos, buff_size - pos,
+				"\tEntry_Index=%d\n", id);
+		} else {
+			pos += scnprintf(buff + pos, buff_size - pos,
+				"\tEntry_Index=%d - Invalid Entry\n", id);
+		}
 
 		pos += ipahal_nat_stringify_entry(nat_type, entry,
 			buff + pos, buff_size - pos);
-
-		++num_entries;
 	}
 
 	if (num_entries)
@@ -1637,6 +1651,7 @@
 	char *pdn_entry;
 	size_t pdn_entry_size;
 	bool entry_zeroed;
+	bool entry_valid;
 	u32 pos = 0;
 
 	IPADBG("\n");
@@ -1654,13 +1669,25 @@
 			pdn_entry, &entry_zeroed);
 		if (result) {
 			IPAERR(
-				"Failed to determine whether the PDN entry is definitely zero");
+				"Failed to determine whether the PDN entry is definitely zero\n");
 			goto bail;
 		}
 		if (entry_zeroed)
 			continue;
 
-		pos += scnprintf(buff + pos, buff_size - pos, "PDN %d: ", i);
+		result = ipahal_nat_is_entry_valid(IPAHAL_NAT_IPV4_PDN,
+			pdn_entry, &entry_valid);
+		if (result) {
+			IPAERR(
+				"Failed to determine whether the PDN entry is valid\n");
+			goto bail;
+		}
+		if (entry_valid)
+			pos += scnprintf(buff + pos, buff_size - pos,
+				"PDN %d: ", i);
+		else
+			pos += scnprintf(buff + pos, buff_size - pos,
+				"PDN %d - Invalid: ", i);
 
 		pos += ipahal_nat_stringify_entry(IPAHAL_NAT_IPV4_PDN,
 			pdn_entry, buff + pos, buff_size - pos);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.c b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.c
index d335ba6..016b4f3 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018 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
@@ -17,6 +17,7 @@
 
 #define IPA_64_LOW_32_MASK (0xFFFFFFFF)
 #define IPA_64_HIGH_32_MASK (0xFFFFFFFF00000000ULL)
+#define IPAHAL_NAT_INVALID_PROTOCOL (0xFF)
 
 static const char *ipahal_nat_type_to_str[IPA_NAT_MAX] = {
 	__stringify(IPAHAL_NAT_IPV4),
@@ -73,6 +74,40 @@
 	return (memcmp(&zero_entry, entry, sizeof(zero_entry))) ? false : true;
 }
 
+static bool ipa_nat_ipv4_is_entry_valid_v_3_0(const void *entry)
+{
+	struct ipa_nat_hw_ipv4_entry *hw_entry =
+		(struct ipa_nat_hw_ipv4_entry *)entry;
+
+	return hw_entry->enable &&
+		hw_entry->protocol != IPAHAL_NAT_INVALID_PROTOCOL;
+}
+
+static bool ipa_nat_ipv4_is_index_entry_valid_v_3_0(const void *entry)
+{
+	struct ipa_nat_hw_indx_entry *hw_entry =
+		(struct ipa_nat_hw_indx_entry *)entry;
+
+	return hw_entry->tbl_entry != 0;
+}
+
+static bool ipa_nat_ipv4_is_pdn_entry_valid_v_4_0(const void *entry)
+{
+	struct ipa_nat_hw_pdn_entry *hw_entry =
+		(struct ipa_nat_hw_pdn_entry *)entry;
+
+	return hw_entry->public_ip != 0;
+}
+
+static bool ipa_nat_ipv6ct_is_entry_valid_v_4_0(const void *entry)
+{
+	struct ipa_nat_hw_ipv6ct_entry *hw_entry =
+		(struct ipa_nat_hw_ipv6ct_entry *)entry;
+
+	return hw_entry->enable &&
+		hw_entry->protocol != IPAHAL_NAT_INVALID_PROTOCOL;
+}
+
 static int ipa_nat_ipv4_stringify_entry_v_3_0(const void *entry,
 	char *buff, size_t buff_size)
 {
@@ -194,11 +229,15 @@
  * 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
+ * @is_entry_valid - CB to determine whether an entry is valid
+ *  Validity criterium depends on entry type. E.g. for NAT base table
+ *   Entry need to be with valid protocol and enabled.
  * @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);
+	bool (*is_entry_valid)(const void *entry);
 	int (*stringify_entry)(const void *entry, char *buff, size_t buff_size);
 };
 
@@ -216,11 +255,13 @@
 	[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_is_entry_valid_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_is_index_entry_valid_v_3_0,
 			ipa_nat_ipv4_index_stringify_entry_v_3_0
 		},
 
@@ -228,16 +269,19 @@
 	[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_is_entry_valid_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_is_pdn_entry_valid_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_is_entry_valid_v_4_0,
 			ipa_nat_ipv6ct_stringify_entry_v_4_0
 		}
 };
@@ -335,6 +379,25 @@
 	return 0;
 }
 
+int ipahal_nat_is_entry_valid(enum ipahal_nat_type nat_type, void *entry,
+	bool *entry_valid)
+{
+	if (WARN(entry == NULL || entry_valid == 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 valid for NAT type=%s\n",
+		ipahal_nat_type_str(nat_type));
+	*entry_valid = ipahal_nat_objs[ipahal_ctx->hw_type][nat_type].
+		is_entry_valid(entry);
+	IPAHAL_DBG("The entry is %svalid\n", (*entry_valid) ? "" : "not ");
+
+	return 0;
+}
+
 int ipahal_nat_stringify_entry(enum ipahal_nat_type nat_type, void *entry,
 	char *buff, size_t buff_size)
 {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.h b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.h
index f99c1a0..2461d3e 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipahal/ipahal_nat.h
@@ -1,4 +1,4 @@
-/* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2017-2018 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
@@ -53,6 +53,18 @@
 	bool *entry_zeroed);
 
 /*
+ * ipahal_nat_is_entry_valid() - Determines whether HW NAT entry is
+ *                                valid.
+ *  Validity criterium depends on entry type. E.g. for NAT base table
+ *   Entry need to be with valid protocol and enabled.
+ * @nat_type: [in] The type of the NAT entry
+ * @entry: [in] The NAT entry
+ * @entry_valid: [out] True if the received entry is valid
+ */
+int ipahal_nat_is_entry_valid(enum ipahal_nat_type nat_type, void *entry,
+	bool *entry_valid);
+
+/*
  * 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