Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea122dda authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: ipa3: read hw tables from debugfs"

parents 05e373d5 39bf45e6
Loading
Loading
Loading
Loading
+170 −1
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@
#define IPA_MAX_MSG_LEN 4096
#define IPA_DBG_CNTR_ON 127265
#define IPA_DBG_CNTR_OFF 127264
#define IPA_DBG_MAX_RULE_IN_TBL 128

const char *ipa3_excp_name[] = {
	__stringify_1(IPA_A5_MUX_HDR_EXCP_RSVD0),
@@ -92,9 +93,13 @@ static struct dentry *dfile_ep_holb;
static struct dentry *dfile_hdr;
static struct dentry *dfile_proc_ctx;
static struct dentry *dfile_ip4_rt;
static struct dentry *dfile_ip4_rt_hw;
static struct dentry *dfile_ip6_rt;
static struct dentry *dfile_ip6_rt_hw;
static struct dentry *dfile_ip4_flt;
static struct dentry *dfile_ip4_flt_hw;
static struct dentry *dfile_ip6_flt;
static struct dentry *dfile_ip6_flt_hw;
static struct dentry *dfile_stats;
static struct dentry *dfile_wstats;
static struct dentry *dfile_wdi_stats;
@@ -695,6 +700,77 @@ static ssize_t ipa3_read_rt(struct file *file, char __user *ubuf, size_t count,
	return 0;
}

static ssize_t ipa3_read_rt_hw(struct file *file, char __user *ubuf,
	size_t count, loff_t *ppos)
{
	int i;
	int j;
	int num_rules;
	struct ipa3_debugfs_rt_entry *entry;
	enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data;
	int num_tbls;

	if (ip == IPA_IP_v4)
		num_tbls = IPA_MEM_PART(v4_rt_num_index);
	else
		num_tbls = IPA_MEM_PART(v6_rt_num_index);

	entry = kzalloc(sizeof(*entry) * IPA_DBG_MAX_RULE_IN_TBL, GFP_KERNEL);
	if (!entry)
		return -ENOMEM;

	mutex_lock(&ipa3_ctx->lock);
	for (j = 0; j < num_tbls; j++) {
		pr_err("== NON HASHABLE TABLE tbl:%d ==\n", j);
		num_rules = IPA_DBG_MAX_RULE_IN_TBL;
		ipa3_rt_read_tbl_from_hw(j, ip, false, entry, &num_rules);
		for (i = 0; i < num_rules; i++) {
			pr_err("rule_idx:%d dst ep:%d L:%u ",
				i, entry[i].dst, entry[i].system);

			if (entry[i].is_proc_ctx)
				pr_err("proc_ctx[32B]:%u attrib_mask:%08x ",
					entry[i].hdr_ofset,
					entry[i].eq_attrib.rule_eq_bitmap);
			else
				pr_err("hdr_ofst[words]:%u attrib_mask:%08x ",
					entry[i].hdr_ofset,
					entry[i].eq_attrib.rule_eq_bitmap);

			pr_err("rule_id:%u prio:%u retain_hdr:%u ",
				entry[i].rule_id, entry[i].prio,
				entry[i].retain_hdr);
			ipa3_attrib_dump_eq(&entry[i].eq_attrib);
		}

		pr_err("== HASHABLE TABLE tbl:%d ==\n", j);
		num_rules = IPA_DBG_MAX_RULE_IN_TBL;
		ipa3_rt_read_tbl_from_hw(j, ip, true, entry, &num_rules);
		for (i = 0; i < num_rules; i++) {
			pr_err("rule_idx:%d dst ep:%d L:%u ",
				i, entry[i].dst, entry[i].system);

			if (entry[i].is_proc_ctx)
				pr_err("proc_ctx[32B]:%u attrib_mask:%08x ",
				entry[i].hdr_ofset,
				entry[i].eq_attrib.rule_eq_bitmap);
			else
				pr_err("hdr_ofst[words]:%u attrib_mask:%08x ",
				entry[i].hdr_ofset,
				entry[i].eq_attrib.rule_eq_bitmap);

			pr_err("rule_id:%u prio:%u retain_hdr:%u ",
				entry[i].rule_id, entry[i].prio,
				entry[i].retain_hdr);
			ipa3_attrib_dump_eq(&entry[i].eq_attrib);
		}
	}
	mutex_unlock(&ipa3_ctx->lock);
	kfree(entry);

	return 0;
}

static ssize_t ipa3_read_proc_ctx(struct file *file, char __user *ubuf,
		size_t count, loff_t *ppos)
{
@@ -800,6 +876,62 @@ static ssize_t ipa3_read_flt(struct file *file, char __user *ubuf, size_t count,
	return 0;
}

static ssize_t ipa3_read_flt_hw(struct file *file, char __user *ubuf,
	size_t count, loff_t *ppos)
{
	int i;
	int j;
	int num_rules;
	struct ipa3_flt_entry *entry;
	enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data;
	u32 rt_tbl_idx;
	u32 bitmap;

	entry = kzalloc(sizeof(*entry) * IPA_DBG_MAX_RULE_IN_TBL, GFP_KERNEL);
	if (!entry)
		return -ENOMEM;

	mutex_lock(&ipa3_ctx->lock);
	for (j = 0; j < ipa3_ctx->ipa_num_pipes; j++) {
		if (!ipa_is_ep_support_flt(j))
			continue;
		pr_err("== NON HASHABLE TABLE ep:%d ==\n", j);
		num_rules = IPA_DBG_MAX_RULE_IN_TBL;
		ipa3_flt_read_tbl_from_hw(j, ip, false, entry, &num_rules);
		for (i = 0; i < num_rules; i++) {
			rt_tbl_idx = entry[i].rule.rt_tbl_idx;
			bitmap = entry[i].rule.eq_attrib.rule_eq_bitmap;
			pr_err("ep_idx:%d rule_idx:%d act:%d rt_tbl_idx:%d ",
				j, i, entry[i].rule.action, rt_tbl_idx);
			pr_err("attrib_mask:%08x retain_hdr:%d ",
				bitmap, entry[i].rule.retain_hdr);
			pr_err("rule_id:%u prio:%u ",
				entry[i].rule_id, entry[i].prio);
			ipa3_attrib_dump_eq(&entry[i].rule.eq_attrib);
		}

		pr_err("== HASHABLE TABLE ep:%d ==\n", j);
		num_rules = IPA_DBG_MAX_RULE_IN_TBL;
		ipa3_flt_read_tbl_from_hw(j, ip, true, entry, &num_rules);
		for (i = 0; i < num_rules; i++) {
			rt_tbl_idx = entry[i].rule.rt_tbl_idx;
			bitmap = entry[i].rule.eq_attrib.rule_eq_bitmap;
			pr_err("ep_idx:%d rule_idx:%d act:%d rt_tbl_idx:%d ",
				j, i, entry[i].rule.action, rt_tbl_idx);
			pr_err("attrib_mask:%08x retain_hdr:%d ",
				bitmap, entry[i].rule.retain_hdr);
			pr_err("rule_id:%u max_prio:%u prio:%u ",
				entry[i].rule_id,
				entry[i].rule.max_prio, entry[i].prio);
			ipa3_attrib_dump_eq(&entry[i].rule.eq_attrib);
		}
	}
	mutex_unlock(&ipa3_ctx->lock);
	kfree(entry);

	return 0;
}

static ssize_t ipa3_read_stats(struct file *file, char __user *ubuf,
		size_t count, loff_t *ppos)
{
@@ -1414,6 +1546,11 @@ const struct file_operations ipa3_rt_ops = {
	.open = ipa3_open_dbg,
};

const struct file_operations ipa3_rt_hw_ops = {
	.read = ipa3_read_rt_hw,
	.open = ipa3_open_dbg,
};

const struct file_operations ipa3_proc_ctx_ops = {
	.read = ipa3_read_proc_ctx,
};
@@ -1423,6 +1560,11 @@ const struct file_operations ipa3_flt_ops = {
	.open = ipa3_open_dbg,
};

const struct file_operations ipa3_flt_hw_ops = {
	.read = ipa3_read_flt_hw,
	.open = ipa3_open_dbg,
};

const struct file_operations ipa3_stats_ops = {
	.read = ipa3_read_stats,
};
@@ -1523,6 +1665,13 @@ void ipa3_debugfs_init(void)
		goto fail;
	}

	dfile_ip4_rt_hw = debugfs_create_file("ip4_rt_hw", read_only_mode, dent,
		(void *)IPA_IP_v4, &ipa3_rt_hw_ops);
	if (!dfile_ip4_rt_hw || IS_ERR(dfile_ip4_rt_hw)) {
		IPAERR("fail to create file for debug_fs ip4 rt hw\n");
		goto fail;
	}

	dfile_ip6_rt = debugfs_create_file("ip6_rt", read_only_mode, dent,
			(void *)IPA_IP_v6, &ipa3_rt_ops);
	if (!dfile_ip6_rt || IS_ERR(dfile_ip6_rt)) {
@@ -1530,6 +1679,13 @@ void ipa3_debugfs_init(void)
		goto fail;
	}

	dfile_ip6_rt_hw = debugfs_create_file("ip6_rt_hw", read_only_mode, dent,
		(void *)IPA_IP_v6, &ipa3_rt_hw_ops);
	if (!dfile_ip6_rt_hw || IS_ERR(dfile_ip6_rt_hw)) {
		IPAERR("fail to create file for debug_fs ip6 rt hw\n");
		goto fail;
	}

	dfile_ip4_flt = debugfs_create_file("ip4_flt", read_only_mode, dent,
			(void *)IPA_IP_v4, &ipa3_flt_ops);
	if (!dfile_ip4_flt || IS_ERR(dfile_ip4_flt)) {
@@ -1537,6 +1693,13 @@ void ipa3_debugfs_init(void)
		goto fail;
	}

	dfile_ip4_flt_hw = debugfs_create_file("ip4_flt_hw", read_only_mode,
			dent, (void *)IPA_IP_v4, &ipa3_flt_hw_ops);
	if (!dfile_ip4_flt_hw || IS_ERR(dfile_ip4_flt_hw)) {
		IPAERR("fail to create file for debug_fs ip4 flt\n");
		goto fail;
	}

	dfile_ip6_flt = debugfs_create_file("ip6_flt", read_only_mode, dent,
			(void *)IPA_IP_v6, &ipa3_flt_ops);
	if (!dfile_ip6_flt || IS_ERR(dfile_ip6_flt)) {
@@ -1544,6 +1707,13 @@ void ipa3_debugfs_init(void)
		goto fail;
	}

	dfile_ip6_flt_hw = debugfs_create_file("ip6_flt_hw", read_only_mode,
			dent, (void *)IPA_IP_v6, &ipa3_flt_hw_ops);
	if (!dfile_ip6_flt_hw || IS_ERR(dfile_ip6_flt_hw)) {
		IPAERR("fail to create file for debug_fs ip6 flt\n");
		goto fail;
	}

	dfile_stats = debugfs_create_file("stats", read_only_mode, dent, 0,
			&ipa3_stats_ops);
	if (!dfile_stats || IS_ERR(dfile_stats)) {
@@ -1635,4 +1805,3 @@ void ipa3_debugfs_remove(void)
void ipa3_debugfs_init(void) {}
void ipa3_debugfs_remove(void) {}
#endif
+132 −25
Original line number Diff line number Diff line
@@ -23,31 +23,6 @@
	(IPA_RULE_HASHABLE):(IPA_RULE_NON_HASHABLE) \
	)

static int ipa3_calc_extra_wrd_bytes(
	const struct ipa_ipfltri_rule_eq *attrib)
{
	int num = 0;

	if (attrib->tos_eq_present)
		num++;
	if (attrib->protocol_eq_present)
		num++;
	if (attrib->tc_eq_present)
		num++;
	num += attrib->num_offset_meq_128;
	num += attrib->num_offset_meq_32;
	num += attrib->num_ihl_offset_meq_32;
	num += attrib->num_ihl_offset_range_16;
	if (attrib->ihl_offset_eq_32_present)
		num++;
	if (attrib->ihl_offset_eq_16_present)
		num++;

	IPADBG("extra bytes number %d\n", num);

	return num;
}

static int ipa3_generate_hw_rule_from_eq(
		const struct ipa_ipfltri_rule_eq *attrib, u8 **buf)
{
@@ -1811,3 +1786,135 @@ int ipa3_set_flt_tuple_mask(int pipe_idx, struct ipa3_hash_tuple *tuple)

	return 0;
}

/**
 * ipa3_flt_read_tbl_from_hw() -Read filtering table from IPA HW
 * @pipe_idx: IPA endpoint index
 * @ip_type: IPv4 or IPv6 table
 * @hashable: hashable or non-hashable table
 * @entry: array to fill the table entries
 * @num_entry: number of entries in entry array. set by the caller to indicate
 *  entry array size. Then set by this function as an output parameter to
 *  indicate the number of entries in the array
 *
 * This function reads the filtering table from IPA SRAM and prepares an array
 * of entries. This function is mainly used for debugging purposes.

 * Returns:	0 on success, negative on failure
 */
int ipa3_flt_read_tbl_from_hw(u32 pipe_idx,
	enum ipa_ip_type ip_type,
	bool hashable,
	struct ipa3_flt_entry entry[],
	int *num_entry)
{
	int tbl_entry_idx;
	u64 tbl_entry_in_hdr_ofst;
	u64 *tbl_entry_in_hdr;
	struct ipa3_flt_rule_hw_hdr *hdr;
	u8 *buf;
	int rule_idx;
	u8 rule_size;
	int i;

	IPADBG("pipe_idx=%d ip_type=%d hashable=%d\n",
		pipe_idx, ip_type, hashable);

	if (pipe_idx >= ipa3_ctx->ipa_num_pipes ||
	    ip_type >= IPA_IP_MAX ||
	    !entry || !num_entry) {
		IPAERR("Invalid params\n");
		return -EFAULT;
	}

	if (!ipa_is_ep_support_flt(pipe_idx)) {
		IPAERR("pipe %d does not support filtering\n", pipe_idx);
		return -EINVAL;
	}

	memset(entry, 0, sizeof(*entry) * (*num_entry));
	/* calculate the offset of the tbl entry */
	tbl_entry_idx = 1; /* to skip the bitmap */
	for (i = 0; i < pipe_idx; i++)
		if (ipa3_ctx->ep_flt_bitmap & (1 << i))
			tbl_entry_idx++;

	if (hashable) {
		if (ip_type == IPA_IP_v4)
			tbl_entry_in_hdr_ofst =
				ipa3_ctx->smem_restricted_bytes +
				IPA_MEM_PART(v4_flt_hash_ofst) +
				tbl_entry_idx * IPA_HW_TBL_HDR_WIDTH;
		else
			tbl_entry_in_hdr_ofst =
				ipa3_ctx->smem_restricted_bytes +
				IPA_MEM_PART(v6_flt_hash_ofst) +
				tbl_entry_idx * IPA_HW_TBL_HDR_WIDTH;
	} else {
		if (ip_type == IPA_IP_v4)
			tbl_entry_in_hdr_ofst =
				ipa3_ctx->smem_restricted_bytes +
				IPA_MEM_PART(v4_flt_nhash_ofst) +
				tbl_entry_idx * IPA_HW_TBL_HDR_WIDTH;
		else
			tbl_entry_in_hdr_ofst =
				ipa3_ctx->smem_restricted_bytes +
				IPA_MEM_PART(v6_flt_nhash_ofst) +
				tbl_entry_idx * IPA_HW_TBL_HDR_WIDTH;
	}

	IPADBG("tbl_entry_in_hdr_ofst=0x%llx\n", tbl_entry_in_hdr_ofst);

	tbl_entry_in_hdr = ipa3_ctx->mmio +
		IPA_SRAM_DIRECT_ACCESS_N_OFST_v3_0(0) + tbl_entry_in_hdr_ofst;

	/* for tables resides in DDR access it from the virtual memory */
	if (*tbl_entry_in_hdr & 0x1) {
		/* local */
		hdr = (void *)(tbl_entry_in_hdr -
			tbl_entry_idx * IPA_HW_TBL_HDR_WIDTH +
			(*tbl_entry_in_hdr - 1) * 16);
	} else {
		/* system */
		if (hashable)
			hdr = ipa3_ctx->flt_tbl[pipe_idx][ip_type].
				curr_mem[IPA_RULE_HASHABLE].base;
		else
			hdr = ipa3_ctx->flt_tbl[pipe_idx][ip_type].
				curr_mem[IPA_RULE_NON_HASHABLE].base;

		if (!hdr)
			hdr = ipa3_ctx->empty_rt_tbl_mem.base;
	}
	IPADBG("*tbl_entry_in_hdr=0x%llx\n", *tbl_entry_in_hdr);
	IPADBG("hdr=0x%p\n", hdr);

	rule_idx = 0;
	while (rule_idx < *num_entry) {
		IPADBG("*((u64 *)hdr)=0x%llx\n", *((u64 *)hdr));
		if (*((u64 *)hdr) == 0)
			break;
		entry[rule_idx].rule.eq_attrib_type = true;
		entry[rule_idx].rule.eq_attrib.rule_eq_bitmap =
			hdr->u.hdr.en_rule;
		entry[rule_idx].rule.action = hdr->u.hdr.action;
		entry[rule_idx].rule.retain_hdr = hdr->u.hdr.retain_hdr;
		entry[rule_idx].rule.rt_tbl_idx = hdr->u.hdr.rt_tbl_idx;
		entry[rule_idx].prio = hdr->u.hdr.priority;
		entry[rule_idx].rule_id = entry->rule.rule_id =
			hdr->u.hdr.rule_id;
		buf = (u8 *)(hdr + 1);
		IPADBG("buf=0x%p\n", buf);

		ipa3_generate_eq_from_hw_rule(&entry[rule_idx].rule.eq_attrib,
			buf, &rule_size);
		IPADBG("rule_size=%d\n", rule_size);
		hdr = (void *)(buf + rule_size);
		IPADBG("hdr=0x%p\n", hdr);
		rule_idx++;
	}

	*num_entry = rule_idx;

	return 0;
}
+37 −0
Original line number Diff line number Diff line
@@ -897,6 +897,28 @@ struct ipa3_tag_completion {
	atomic_t cnt;
};

/**
 * struct ipa3_debugfs_rt_entry - IPA routing table entry for debugfs
 * @eq_attrib: equation attributes for the rule
 * @retain_hdr: retain header when hit this rule
 * @prio: rule 10bit priority which defines the order of the rule
 * @rule_id: rule 10bit ID to be returned in packet status
 * @dst: destination endpoint
 * @hdr_ofset: header offset to be added
 * @system: rule resides in system memory
 * @is_proc_ctx: indicates whether the rules points to proc_ctx or header
 */
struct ipa3_debugfs_rt_entry {
	struct ipa_ipfltri_rule_eq eq_attrib;
	uint8_t retain_hdr;
	u16 prio;
	u16 rule_id;
	u8 dst;
	u8 hdr_ofset;
	u8 system;
	u8 is_proc_ctx;
};

struct ipa3_controller;

/**
@@ -2203,4 +2225,19 @@ void ipa3_set_resorce_groups_min_max_limits(void);
void ipa3_suspend_apps_pipes(bool suspend);
void ipa3_flow_control(enum ipa_client_type ipa_client, bool enable,
			uint32_t qmap_id);
int ipa3_generate_eq_from_hw_rule(
	struct ipa_ipfltri_rule_eq *attrib, u8 *buf, u8 *rule_size);
int ipa3_flt_read_tbl_from_hw(u32 pipe_idx,
	enum ipa_ip_type ip_type,
	bool hashable,
	struct ipa3_flt_entry entry[],
	int *num_entry);
int ipa3_rt_read_tbl_from_hw(u32 tbl_idx,
	enum ipa_ip_type ip_type,
	bool hashable,
	struct ipa3_debugfs_rt_entry entry[],
	int *num_entry);

int ipa3_calc_extra_wrd_bytes(const struct ipa_ipfltri_rule_eq *attrib);

#endif /* _IPA3_I_H_ */
+128 −0
Original line number Diff line number Diff line
@@ -1810,3 +1810,131 @@ int ipa3_set_rt_tuple_mask(int tbl_idx, struct ipa3_hash_tuple *tuple)

	return 0;
}

/**
 * ipa3_rt_read_tbl_from_hw() -Read routing table from IPA HW
 * @tbl_idx: routing table index
 * @ip_type: IPv4 or IPv6 table
 * @hashable: hashable or non-hashable table
 * @entry: array to fill the table entries
 * @num_entry: number of entries in entry array. set by the caller to indicate
 *  entry array size. Then set by this function as an output parameter to
 *  indicate the number of entries in the array
 *
 * This function reads the filtering table from IPA SRAM and prepares an array
 * of entries. This function is mainly used for debugging purposes.
 *
 * Returns:	0 on success, negative on failure
 */
int ipa3_rt_read_tbl_from_hw(u32 tbl_idx,
	enum ipa_ip_type ip_type,
	bool hashable,
	struct ipa3_debugfs_rt_entry entry[],
	int *num_entry)
{
	u64 tbl_entry_in_hdr_ofst;
	u64 *tbl_entry_in_hdr;
	struct ipa3_rt_rule_hw_hdr *hdr;
	u8 *buf;
	int rule_idx;
	u8 rule_size;

	IPADBG("tbl_idx=%d ip_type=%d hashable=%d\n",
		tbl_idx, ip_type, hashable);

	if (ip_type == IPA_IP_v4 && tbl_idx >= IPA_MEM_PART(v4_rt_num_index)) {
		IPAERR("Invalid params\n");
		return -EFAULT;
	}

	if (ip_type == IPA_IP_v6 && tbl_idx >= IPA_MEM_PART(v6_rt_num_index)) {
		IPAERR("Invalid params\n");
		return -EFAULT;
	}

	memset(entry, 0, sizeof(*entry) * (*num_entry));
	if (hashable) {
		if (ip_type == IPA_IP_v4)
			tbl_entry_in_hdr_ofst =
				ipa3_ctx->smem_restricted_bytes +
				IPA_MEM_PART(v4_rt_hash_ofst) +
				tbl_idx * IPA_HW_TBL_HDR_WIDTH;
		else
			tbl_entry_in_hdr_ofst =
				ipa3_ctx->smem_restricted_bytes +
				IPA_MEM_PART(v6_rt_hash_ofst) +
				tbl_idx * IPA_HW_TBL_HDR_WIDTH;
	} else {
		if (ip_type == IPA_IP_v4)
			tbl_entry_in_hdr_ofst =
				ipa3_ctx->smem_restricted_bytes +
				IPA_MEM_PART(v4_rt_nhash_ofst) +
				tbl_idx * IPA_HW_TBL_HDR_WIDTH;
		else
			tbl_entry_in_hdr_ofst =
				ipa3_ctx->smem_restricted_bytes +
				IPA_MEM_PART(v6_rt_nhash_ofst) +
				tbl_idx * IPA_HW_TBL_HDR_WIDTH;
	}

	IPADBG("tbl_entry_in_hdr_ofst=0x%llx\n", tbl_entry_in_hdr_ofst);

	tbl_entry_in_hdr = ipa3_ctx->mmio +
		IPA_SRAM_DIRECT_ACCESS_N_OFST_v3_0(0) + tbl_entry_in_hdr_ofst;

	/* for tables which reside in DDR access it from the virtual memory */
	if (*tbl_entry_in_hdr & 0x0) {
		/* system */
		struct ipa3_rt_tbl_set *set;
		struct ipa3_rt_tbl *tbl;

		set = &ipa3_ctx->rt_tbl_set[ip_type];
		hdr = NULL;
		list_for_each_entry(tbl, &set->head_rt_tbl_list, link) {
			if (tbl->idx == tbl_idx)
				hdr = tbl->curr_mem[hashable ?
					IPA_RULE_HASHABLE :
					IPA_RULE_NON_HASHABLE].base;
		}

		if (!hdr)
			hdr = ipa3_ctx->empty_rt_tbl_mem.base;
	} else {
		/* local */
		hdr = (void *)(tbl_entry_in_hdr -
			tbl_idx * IPA_HW_TBL_HDR_WIDTH +
			(*tbl_entry_in_hdr - 1) * 16);
	}
	IPADBG("*tbl_entry_in_hdr=0x%llx\n", *tbl_entry_in_hdr);
	IPADBG("hdr=0x%p\n", hdr);


	rule_idx = 0;
	while (rule_idx < *num_entry) {
		IPADBG("*((u64 *)hdr)=0x%llx\n", *((u64 *)hdr));
		if (*((u64 *)hdr) == 0)
			break;

		entry[rule_idx].eq_attrib.rule_eq_bitmap = hdr->u.hdr.en_rule;
		entry[rule_idx].retain_hdr = hdr->u.hdr.retain_hdr;
		entry[rule_idx].prio = hdr->u.hdr.priority;
		entry[rule_idx].rule_id = hdr->u.hdr.rule_id;
		entry[rule_idx].dst = hdr->u.hdr.pipe_dest_idx;
		entry[rule_idx].hdr_ofset = hdr->u.hdr.hdr_offset;
		entry[rule_idx].is_proc_ctx = hdr->u.hdr.proc_ctx;
		entry[rule_idx].system = hdr->u.hdr.system;
		buf = (u8 *)(hdr + 1);
		IPADBG("buf=0x%p\n", buf);

		ipa3_generate_eq_from_hw_rule(&entry[rule_idx].eq_attrib, buf,
			&rule_size);
		IPADBG("rule_size=%d\n", rule_size);
		hdr = (void *)(buf + rule_size);
		IPADBG("hdr=0x%p\n", hdr);
		rule_idx++;
	}

	*num_entry = rule_idx;

	return 0;
}
+244 −0
Original line number Diff line number Diff line
@@ -5046,3 +5046,247 @@ bail:
			mem.phys_base);
	return res;
}

/**
 * ipa3_calc_extra_wrd_bytes()- Calculate the number of extra words for eq
 * @attrib: equation attribute
 *
 * Return value: 0 on success, negative otherwise
 */
int ipa3_calc_extra_wrd_bytes(const struct ipa_ipfltri_rule_eq *attrib)
{
	int num = 0;

	if (attrib->tos_eq_present)
		num++;
	if (attrib->protocol_eq_present)
		num++;
	if (attrib->tc_eq_present)
		num++;
	num += attrib->num_offset_meq_128;
	num += attrib->num_offset_meq_32;
	num += attrib->num_ihl_offset_meq_32;
	num += attrib->num_ihl_offset_range_16;
	if (attrib->ihl_offset_eq_32_present)
		num++;
	if (attrib->ihl_offset_eq_16_present)
		num++;

	IPADBG("extra bytes number %d\n", num);

	return num;
}

/**
 * ipa3_calc_extra_wrd_bytes()- generate an equation from rule read from IPA HW
 * @attrib: equation attribute
 * @buf: raw rule in IPA SRAM
 * @rule_size: size of the rule pointed by buf
 *
 * Return value: 0 on success, negative otherwise
 */
int ipa3_generate_eq_from_hw_rule(
	struct ipa_ipfltri_rule_eq *attrib, u8 *buf, u8 *rule_size)
{
	int num_offset_meq_32;
	int num_ihl_offset_range_16;
	int num_ihl_offset_meq_32;
	int num_offset_meq_128;
	int extra_bytes;
	u8 *extra;
	u8 *rest;
	int i;

	IPADBG("rule_eq_bitmap=0x%x\n", attrib->rule_eq_bitmap);
	if (attrib->rule_eq_bitmap & IPA_TOS_EQ)
		attrib->tos_eq_present = true;
	if (attrib->rule_eq_bitmap & IPA_PROTOCOL_EQ)
		attrib->protocol_eq_present = true;
	if (attrib->rule_eq_bitmap & IPA_OFFSET_MEQ32_0)
		attrib->num_offset_meq_32++;
	if (attrib->rule_eq_bitmap & IPA_OFFSET_MEQ32_1)
		attrib->num_offset_meq_32++;
	if (attrib->rule_eq_bitmap & IPA_IHL_OFFSET_RANGE16_0)
		attrib->num_ihl_offset_range_16++;
	if (attrib->rule_eq_bitmap & IPA_IHL_OFFSET_RANGE16_1)
		attrib->num_ihl_offset_range_16++;
	if (attrib->rule_eq_bitmap & IPA_IHL_OFFSET_EQ_16)
		attrib->ihl_offset_eq_16_present = true;
	if (attrib->rule_eq_bitmap & IPA_IHL_OFFSET_EQ_32)
		attrib->ihl_offset_eq_32_present = true;
	if (attrib->rule_eq_bitmap & IPA_IHL_OFFSET_MEQ32_0)
		attrib->num_ihl_offset_meq_32++;
	if (attrib->rule_eq_bitmap & IPA_OFFSET_MEQ128_0)
		attrib->num_offset_meq_128++;
	if (attrib->rule_eq_bitmap & IPA_OFFSET_MEQ128_1)
		attrib->num_offset_meq_128++;
	if (attrib->rule_eq_bitmap & IPA_TC_EQ)
		attrib->tc_eq_present = true;
	if (attrib->rule_eq_bitmap & IPA_FL_EQ)
		attrib->fl_eq_present = true;
	if (attrib->rule_eq_bitmap & IPA_PROTOCOL_EQ)
		attrib->protocol_eq_present = true;
	if (attrib->rule_eq_bitmap & IPA_IHL_OFFSET_MEQ32_1)
		attrib->num_ihl_offset_meq_32++;
	if (attrib->rule_eq_bitmap & IPA_METADATA_COMPARE)
		attrib->metadata_meq32_present = true;
	if (attrib->rule_eq_bitmap & IPA_IS_FRAG)
		attrib->ipv4_frag_eq_present = true;

	extra_bytes = ipa3_calc_extra_wrd_bytes(attrib);
	/*
	 * only 3 eq does not have extra word param, 13 out of 16 is the number
	 * of equations that needs extra word param
	 */
	if (extra_bytes > 13) {
		IPAERR("too much extra bytes\n");
		return -EPERM;
	} else if (extra_bytes > IPA_HW_TBL_HDR_WIDTH) {
		/* two extra words */
		extra = buf;
		rest = buf + IPA_HW_TBL_HDR_WIDTH * 2;
	} else if (extra_bytes > 0) {
		/* single exra word */
		extra = buf;
		rest = buf + IPA_HW_TBL_HDR_WIDTH;
	} else {
		/* no extra words */
		extra = NULL;
		rest = buf;
	}
	IPADBG("buf=0x%p extra=0x%p rest=0x%p\n", buf, extra, rest);

	num_offset_meq_32 = attrib->num_offset_meq_32;
	num_ihl_offset_range_16 = attrib->num_ihl_offset_range_16;
	num_ihl_offset_meq_32 = attrib->num_ihl_offset_meq_32;
	num_offset_meq_128 = attrib->num_offset_meq_128;

	if (attrib->tos_eq_present)
		attrib->tos_eq = *extra++;

	if (attrib->protocol_eq_present)
		attrib->protocol_eq = *extra++;

	if (attrib->tc_eq_present)
		attrib->tc_eq = *extra++;

	if (num_offset_meq_128) {
		attrib->offset_meq_128[0].offset = *extra++;
		for (i = 0; i < 8; i++)
			attrib->offset_meq_128[0].mask[i] = *rest++;
		for (i = 0; i < 8; i++)
			attrib->offset_meq_128[0].value[i] = *rest++;
		for (i = 8; i < 16; i++)
			attrib->offset_meq_128[0].mask[i] = *rest++;
		for (i = 8; i < 16; i++)
			attrib->offset_meq_128[0].value[i] = *rest++;
		num_offset_meq_128--;
	}

	if (num_offset_meq_128) {
		attrib->offset_meq_128[1].offset = *extra++;
		for (i = 0; i < 8; i++)
			attrib->offset_meq_128[1].mask[i] = *rest++;
		for (i = 0; i < 8; i++)
			attrib->offset_meq_128[1].value[i] = *rest++;
		for (i = 8; i < 16; i++)
			attrib->offset_meq_128[1].mask[i] = *rest++;
		for (i = 8; i < 16; i++)
			attrib->offset_meq_128[1].value[i] = *rest++;
		num_offset_meq_128--;
	}

	if (num_offset_meq_32) {
		attrib->offset_meq_32[0].offset = *extra++;
		attrib->offset_meq_32[0].mask = *((u32 *)rest);
		rest += 4;
		attrib->offset_meq_32[0].value = *((u32 *)rest);
		rest += 4;
		num_offset_meq_32--;
	}
	IPADBG("buf=0x%p extra=0x%p rest=0x%p\n", buf, extra, rest);

	if (num_offset_meq_32) {
		attrib->offset_meq_32[1].offset = *extra++;
		attrib->offset_meq_32[1].mask = *((u32 *)rest);
		rest += 4;
		attrib->offset_meq_32[1].value = *((u32 *)rest);
		rest += 4;
		num_offset_meq_32--;
	}
	IPADBG("buf=0x%p extra=0x%p rest=0x%p\n", buf, extra, rest);

	if (num_ihl_offset_meq_32) {
		attrib->ihl_offset_meq_32[0].offset = *extra++;
		attrib->ihl_offset_meq_32[0].mask = *((u32 *)rest);
		rest += 4;
		attrib->ihl_offset_meq_32[0].value = *((u32 *)rest);
		rest += 4;
		num_ihl_offset_meq_32--;
	}

	if (num_ihl_offset_meq_32) {
		attrib->ihl_offset_meq_32[1].offset = *extra++;
		attrib->ihl_offset_meq_32[1].mask = *((u32 *)rest);
		rest += 4;
		attrib->ihl_offset_meq_32[1].value = *((u32 *)rest);
		rest += 4;
		num_ihl_offset_meq_32--;
	}

	if (attrib->metadata_meq32_present) {
		attrib->metadata_meq32.mask = *((u32 *)rest);
		rest += 4;
		attrib->metadata_meq32.value = *((u32 *)rest);
		rest += 4;
	}

	if (num_ihl_offset_range_16) {
		attrib->ihl_offset_range_16[0].offset = *extra++;
		attrib->ihl_offset_range_16[0].range_high = *((u16 *)rest);
		rest += 2;
		attrib->ihl_offset_range_16[0].range_low = *((u16 *)rest);
		rest += 2;
		num_ihl_offset_range_16--;
	}
	if (num_ihl_offset_range_16) {
		attrib->ihl_offset_range_16[1].offset = *extra++;
		attrib->ihl_offset_range_16[1].range_high = *((u16 *)rest);
		rest += 2;
		attrib->ihl_offset_range_16[1].range_low = *((u16 *)rest);
		rest += 2;
		num_ihl_offset_range_16--;
	}

	if (attrib->ihl_offset_eq_32_present) {
		attrib->ihl_offset_eq_32.offset = *extra++;
		attrib->ihl_offset_eq_32.value = *((u32 *)rest);
		rest += 4;
	}

	if (attrib->ihl_offset_eq_16_present) {
		attrib->ihl_offset_eq_16.offset = *extra++;
		attrib->ihl_offset_eq_16.value = *((u16 *)rest);
		rest += 4;
	}

	if (attrib->fl_eq_present) {
		attrib->fl_eq = *((u32 *)rest);
		rest += 4;
	}

	IPADBG("before align buf=0x%p extra=0x%p rest=0x%p\n",
		buf, extra, rest);
	/* align to 64 bit */
	rest = (u8 *)(((u32)rest + IPA_HW_RULE_START_ALIGNMENT) &
		~IPA_HW_RULE_START_ALIGNMENT);

	IPADBG("after align buf=0x%p extra=0x%p rest=0x%p\n",
		buf, extra, rest);
	IPADBG("rest - buf=0x%x\n", rest - buf);

	*rule_size = rest - buf;
	IPADBG("*rule_size=0x%x\n", *rule_size);

	return 0;
}