Loading drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +170 −1 Original line number Diff line number Diff line Loading @@ -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), Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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, }; Loading @@ -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, }; Loading Loading @@ -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)) { Loading @@ -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)) { Loading @@ -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)) { Loading @@ -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)) { Loading Loading @@ -1635,4 +1805,3 @@ void ipa3_debugfs_remove(void) void ipa3_debugfs_init(void) {} void ipa3_debugfs_remove(void) {} #endif drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +132 −25 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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; } drivers/platform/msm/ipa/ipa_v3/ipa_i.h +37 −0 Original line number Diff line number Diff line Loading @@ -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; /** Loading Loading @@ -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_ */ drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +128 −0 Original line number Diff line number Diff line Loading @@ -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; } drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +244 −0 Original line number Diff line number Diff line Loading @@ -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; } Loading
drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +170 −1 Original line number Diff line number Diff line Loading @@ -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), Loading Loading @@ -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; Loading Loading @@ -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) { Loading Loading @@ -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) { Loading Loading @@ -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, }; Loading @@ -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, }; Loading Loading @@ -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)) { Loading @@ -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)) { Loading @@ -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)) { Loading @@ -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)) { Loading Loading @@ -1635,4 +1805,3 @@ void ipa3_debugfs_remove(void) void ipa3_debugfs_init(void) {} void ipa3_debugfs_remove(void) {} #endif
drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +132 −25 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading @@ -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; }
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +37 −0 Original line number Diff line number Diff line Loading @@ -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; /** Loading Loading @@ -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_ */
drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +128 −0 Original line number Diff line number Diff line Loading @@ -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; }
drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +244 −0 Original line number Diff line number Diff line Loading @@ -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; }