From 90dd8e86859c147626ba52959054825e38922df5 Mon Sep 17 00:00:00 2001 From: Prasad Arepalli Date: Fri, 19 Jul 2024 18:50:57 +0530 Subject: [PATCH] msm: ipa: Add debugfs nodes to install/remove xr wlan filters Enable ipa debugfs nodes to install/remove filters at wlan fw from ipa driver and handle accordingly. Change-Id: I856a1f8cbae38432fdbb865090747295c03bc691 Signed-off-by: Prasad Arepalli --- drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 506 ++++++++++++++++++ drivers/platform/msm/ipa/ipa_v3/ipa_i.h | 1 + 2 files changed, 507 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index 94c0447872..fc4861c28e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -26,6 +26,7 @@ #define IPA_DBG_MAX_RULE_IN_TBL 128 #define IPA_DBG_ACTIVE_CLIENT_BUF_SIZE ((IPA3_ACTIVE_CLIENTS_LOG_LINE_LEN \ * IPA3_ACTIVE_CLIENTS_LOG_BUFFER_SIZE_LINES) + IPA_MAX_MSG_LEN) +#define MAX_UC_BUFF_SIZE (1 * 1024UL * 1024UL) #define IPA_DUMP_STATUS_FIELD(f) \ pr_err(#f "=0x%x\n", status->f) @@ -144,6 +145,8 @@ static char *active_clients_buf; static s8 ep_reg_idx; static void *ipa_ipc_low_buff; +static u8 active_streams[MAX_STREAMS]; +static u8 active_flt_cnt; static ssize_t ipa3_read_gen_reg(struct file *file, char __user *ubuf, @@ -3542,6 +3545,491 @@ free_rt: return 0; } +static inline u32 ip_to_int(u8 a, u8 b, u8 c, u8 d) +{ + // IP to int is first octet * 256^3 + second octet * 256^2 + third octet * 256 + fourth oct + // Bit shifting is quicker than multiplication + // 2^24 = 256^3, 2^16 = 256^2, 256 = 2^8 + return (a << 24) + (b << 16) + (c << 8) + d; +} + +static u32 string_ip_to_integer_ip(char *str_ip) +{ + u8 a = 0, b = 0, c = 0, d = 0; + char *found = NULL; + u32 ip = 0; + + if (!str_ip) + return ip; + + found = strsep(&str_ip, "."); + if (!found || kstrtou8(found, 0, &a)) + goto err; + + found = strsep(&str_ip, "."); + if (!found || kstrtou8(found, 0, &b)) + goto err; + + found = strsep(&str_ip, "."); + if (!found || kstrtou8(found, 0, &c)) + goto err; + + found = strsep(&str_ip, "."); + if (!found || kstrtou8(found, 0, &d)) + goto err; + + pr_info("IP ADDR -> %d.%d.%d.%d\n", a, b, c, d); + ip = ip_to_int(a, b, c, d); + +err: + return ip; +} + +static ssize_t ipa_xr_add_flt_to_wlan(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + u32 src_ip[MAX_STREAMS] = {0}; + u32 dst_ip[MAX_STREAMS] = {0}; + u16 src_port[MAX_STREAMS] = {0}; + u16 dst_port[MAX_STREAMS] = {0}; + u8 prot[MAX_STREAMS] = {0}; + u8 num_filters = 0; + ssize_t missing = 0; + char *sptr = NULL; + char *token = NULL; + struct ipa_wdi_opt_dpath_flt_add_cb_params flt_add_req; + int result = 0; + u8 i = 0, j = 0, stream_id = 0; + + if (count >= sizeof(dbg_buff)) + return -EFAULT; + + memset(dbg_buff, 0, sizeof(dbg_buff)); + missing = copy_from_user(dbg_buff, buf, count); + if (missing) + return -EFAULT; + + dbg_buff[count] = '\0'; + sptr = dbg_buff; + + /* Getting the number of filters configured by user */ + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &num_filters)) + return -EINVAL; + + IPADBG("Number of filters %d\n", num_filters); + + if (num_filters > MAX_STREAMS || num_filters == 0) { + IPAERR("Number of filters is zero or more than max_streams, so it is invalid\n"); + return -EINVAL; + } + + if (!atomic_read(&ipa3_ctx->ipa_xr_wdi_flt_rsv_status)) { + memset(active_streams, 0, sizeof(active_streams)); + active_flt_cnt = 0; + } + + if (active_flt_cnt + num_filters > MAX_STREAMS) { + IPAERR("Active filter count of %u exceeded maximum streams of %u\n", + active_flt_cnt, MAX_STREAMS); + return -EFAULT; + } + + for (i = 0; i < num_filters; i++) { + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + src_ip[i] = string_ip_to_integer_ip(token); + if (!src_ip[i]) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + dst_ip[i] = string_ip_to_integer_ip(token); + if (!dst_ip[i]) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + /* Range detection will be done by this API */ + if (kstrtou16(token, 0, &src_port[i]) || src_port[i] == 0) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + /* Range detection will be done by this API */ + if (kstrtou16(token, 0, &dst_port[i]) || dst_port[i] == 0) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &prot[i]) || prot[i] != IPPROTO_UDP) + return -EINVAL; + } + + if (!atomic_read(&ipa3_ctx->ipa_xr_wdi_flt_rsv_status)) { + result = ipa_xr_wdi_opt_dpath_rsrv_filter_req(); + if (result) { + IPAERR("Filter reservation failed at WLAN %d\n", result); + return result; + } + } + + for (i = 0; i < num_filters; i++) { + for (j = 0; j < MAX_STREAMS; j++) { + if (active_streams[j] == 0) { + stream_id = j; + break; + } + } + + IPADBG("Available stream id %u\n", stream_id); + memset(&flt_add_req, 0, sizeof(struct ipa_wdi_opt_dpath_flt_add_cb_params)); + flt_add_req.num_tuples = 1; + flt_add_req.flt_info[0].version = 0; + flt_add_req.flt_info[0].ipv4_addr.ipv4_saddr = src_ip[i]; + flt_add_req.flt_info[0].ipv4_addr.ipv4_daddr = dst_ip[i]; + flt_add_req.flt_info[0].sport = src_port[i]; + flt_add_req.flt_info[0].dport = dst_port[i]; + flt_add_req.flt_info[0].protocol = prot[i]; + + IPADBG("IPv4 saddr:%lu, daddr:%lu IPv4 sport:%u, dport:%u protocol:%u\n", + flt_add_req.flt_info[0].ipv4_addr.ipv4_saddr, + flt_add_req.flt_info[0].ipv4_addr.ipv4_daddr, + flt_add_req.flt_info[0].sport, + flt_add_req.flt_info[0].dport, + flt_add_req.flt_info[0].protocol); + + result = ipa_xr_wdi_opt_dpath_add_filter_req(&flt_add_req, stream_id); + if (result) { + IPAERR("Failed to add filters at wlan\n"); + return -EPERM; + } + active_streams[stream_id] = 1; + active_flt_cnt++; + } + + return count; +} + +static ssize_t ipa_xr_remove_flt_to_wlan(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + char *sptr = NULL, *token = NULL; + u8 flt_opt = 0; + int result = 0; + ssize_t missing = 0; + + if (active_flt_cnt == 0) { + IPAERR("No active filters to delete\n"); + return -EFAULT; + } + + if (count >= sizeof(dbg_buff)) + return -EFAULT; + + memset(dbg_buff, 0, sizeof(dbg_buff)); + missing = copy_from_user(dbg_buff, buf, count); + if (missing) + return -EFAULT; + + dbg_buff[count] = '\0'; + sptr = dbg_buff; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &flt_opt)) + return -EINVAL; + + if (flt_opt > MAX_STREAMS) { + IPAERR("Flt_opt is more than max_streams, so it is invalid\n"); + return -EINVAL; + } + + if (!atomic_read(&ipa3_ctx->ipa_xr_wdi_flt_rsv_status)) { + IPAERR("No existing filters at wlan\n"); + memset(active_streams, 0, sizeof(active_streams)); + active_flt_cnt = 0; + return -EPERM; + } + + /* flt_opt == 0, will remove all streams filters from wlan */ + if (!flt_opt) { + result = ipa_xr_wdi_opt_dpath_remove_all_filter_req(); + if (result) { + IPAERR("Failed to remove all streams filters from wlan\n"); + return -EPERM; + } + active_flt_cnt = 0; + memset(active_streams, 0, sizeof(active_streams)); + IPADBG("Removed all streams existing filters\n"); + return count; + } + + if (active_streams[flt_opt-1] == 0) { + IPADBG("Stream_ID: %d filter is already deleted at WLAN\n", flt_opt); + return -EPERM; + } + + /* Based on stream ID removing filters from wlan */ + result = ipa_xr_wdi_opt_dpath_remove_filter_req(flt_opt - 1); + if (result) { + IPAERR("Failed to remove stream-id: %d filter from wlan\n", flt_opt); + return -EPERM; + } + IPADBG("Removed stream-id: %d filter from wlan\n", flt_opt); + active_flt_cnt--; + active_streams[flt_opt - 1] = 0; + return count; +} + +#ifdef CONFIG_IPA_RTP +static ssize_t ipa_xr_add_flt_to_ipa_wlan(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + struct traffic_tuple_info tuple_info; + u32 src_ip = 0; + u32 dst_ip = 0; + u16 src_port = 0; + u16 dst_port = 0; + u8 prot = 0; + ssize_t missing = 0; + char *sptr = NULL, *token = NULL; + int result = 0; + u32 bs_buff_size = 0; + u8 stream_id = 0; + + struct bitstream_buffers_to_uc data; + dma_addr_t bs_phys_base[MAX_BUFF], mb_phys_base[MAX_BUFF]; + void *bs_va[MAX_BUFF] = {NULL}, *mb_va[MAX_BUFF] = {NULL}; + int i = 0, j = 0; + + if (!atomic_read(&ipa3_ctx->ipa_xr_wdi_flt_rsv_status)) { + memset(active_streams, 0, sizeof(active_streams)); + active_flt_cnt = 0; + } + + if (active_flt_cnt >= MAX_STREAMS) { + IPAERR("Maximum filters already installed: %u\n", active_flt_cnt); + return -EFAULT; + } + + if (count >= sizeof(dbg_buff)) + return -EFAULT; + + memset(dbg_buff, 0, sizeof(dbg_buff)); + missing = copy_from_user(dbg_buff, buf, count); + if (missing) + return -EFAULT; + + dbg_buff[count] = '\0'; + sptr = dbg_buff; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + src_ip = string_ip_to_integer_ip(token); + if (!src_ip) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + dst_ip = string_ip_to_integer_ip(token); + if (!dst_ip) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &src_port) || src_port == 0) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &dst_port) || dst_port == 0) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &prot) || prot != IPPROTO_UDP) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou32(token, 0, &bs_buff_size) || bs_buff_size > MAX_UC_BUFF_SIZE) + return -EINVAL; + + for (j = 0; j < MAX_STREAMS; j++) { + if (active_streams[j] == 0) { + stream_id = j; + break; + } + } + + IPADBG("Available stream id %u\n", stream_id); + IPADBG("Framing bitstream & Metadata buffer of size :%lu\n", bs_buff_size); + + data.buff_cnt = MAX_BUFF; + data.cookie = 0x1234; + for (i = 0; i < data.buff_cnt; i++) { + data.bs_info[i].stream_id = stream_id; + data.bs_info[i].fence_id = i; + bs_va[i] = dma_alloc_coherent(ipa3_ctx->rtp_pdev, bs_buff_size, + &bs_phys_base[i], GFP_KERNEL); + if (!bs_va[i]) { + IPADBG("Failed to allocate bitstream buffers of size: %u\n", + bs_buff_size); + goto free_bs_mb_buff; + } + + IPADBG("Bit stream buffer va is 0x%x\n", bs_va[i]); + IPADBG("Bit stream buffer iova is 0x%x\n", bs_phys_base[i]); + data.bs_info[i].buff_addr = bs_phys_base[i]; + data.bs_info[i].buff_fd = 0; + data.bs_info[i].buff_size = bs_buff_size; + mb_va[i] = dma_alloc_coherent(ipa3_ctx->rtp_pdev, IPA_MAX_MSG_LEN, + &mb_phys_base[i], GFP_KERNEL); + if (!mb_va[i]) { + IPADBG("Failed to allocate metadata buffers of size: %u\n", + IPA_MAX_MSG_LEN); + dma_free_coherent(ipa3_ctx->rtp_pdev, bs_buff_size, + bs_va[i], bs_phys_base[i]); + goto free_bs_mb_buff; + } + + IPADBG("Metadata buffer va is 0x%x\n", mb_va[i]); + IPADBG("Metadata buffer iova is 0x%x\n", mb_phys_base[i]); + data.bs_info[i].meta_buff_addr = mb_phys_base[i]; + data.bs_info[i].meta_buff_fd = 0; + data.bs_info[i].meta_buff_size = IPA_MAX_MSG_LEN; + } + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + result = ipa3_uc_send_add_bitstream_buffers_cmd(&data); + if (result) { + IPAERR("Failed to send bitstream buffers to uC\n"); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + goto free_bs_mb_buff; + } + + tuple_info.ts_info.no_of_openframe = 3; + tuple_info.ts_info.max_pkt_frame = 256; + tuple_info.ts_info.stream_type = 0; + tuple_info.ts_info.reorder_timeout = 100; + tuple_info.ts_info.num_slices_per_frame = 0; + + tuple_info.ip_type = 0; + tuple_info.ip_info.ipv4.src_port_number = src_port; + tuple_info.ip_info.ipv4.dst_port_number = dst_port; + tuple_info.ip_info.ipv4.src_ip = src_ip; + tuple_info.ip_info.ipv4.dst_ip = dst_ip; + tuple_info.ip_info.ipv4.protocol = prot; + + IPADBG("IPv4 saddr:0x%x, daddr:0x%x\n", + tuple_info.ip_info.ipv4.src_ip, + tuple_info.ip_info.ipv4.dst_ip); + IPADBG("IPv4 sport:%u, dport:%u\n", + tuple_info.ip_info.ipv4.src_port_number, + tuple_info.ip_info.ipv4.dst_port_number); + + if (ipa3_install_rtp_hdr_proc_rt_flt_rules(&tuple_info, stream_id) || + ipa3_tuple_info_cmd_to_wlan_uc(&tuple_info, stream_id)) { + IPAERR("Failed to install rtp hdr proc and flt rules or filters at WLAN\n"); + ipa3_delete_rtp_hdr_proc_rt_flt_rules(stream_id); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + goto free_bs_mb_buff; + } + active_flt_cnt++; + active_streams[stream_id] = 1; + IPADBG("Sent bitstream and metadata buffer, filter info to uC or WLAN\n"); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + + return count; + +free_bs_mb_buff: + /* ith bs_buff is already freed above */ + for (j = i-1; j >= 0; j--) { + if (bs_va[j]) + dma_free_coherent(ipa3_ctx->rtp_pdev, bs_buff_size, + bs_va[j], bs_phys_base[j]); + if (mb_va[j]) + dma_free_coherent(ipa3_ctx->rtp_pdev, IPA_MAX_MSG_LEN, + mb_va[j], mb_phys_base[j]); + } + return -ENOMEM; +} + +static ssize_t ipa_xr_remove_flt_to_ipa_wlan(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + char *sptr = NULL, *token = NULL; + u8 stream_id = 0; + ssize_t missing = 0; + struct remove_bitstream_buffers rmv_sid_req; + + if (active_flt_cnt == 0) { + IPAERR("No active filters to delete\n"); + return -EFAULT; + } + + if (!atomic_read(&ipa3_ctx->ipa_xr_wdi_flt_rsv_status)) { + IPAERR("No existing filters at wlan\n"); + memset(active_streams, 0, sizeof(active_streams)); + active_flt_cnt = 0; + return -EPERM; + } + + if (count >= sizeof(dbg_buff)) + return -EFAULT; + + memset(dbg_buff, 0, sizeof(dbg_buff)); + missing = copy_from_user(dbg_buff, buf, count); + if (missing) + return -EFAULT; + + dbg_buff[count] = '\0'; + sptr = dbg_buff; + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou8(token, 0, &stream_id)) + return -EINVAL; + + if (stream_id > MAX_STREAMS || stream_id == 0) { + IPAERR("Stream_id is zero or more than %u. Exit\n", MAX_STREAMS); + return -EINVAL; + } + + IPA_ACTIVE_CLIENTS_INC_SIMPLE(); + + rmv_sid_req.stream_id = stream_id; + if (ipa3_uc_send_remove_stream_cmd(&rmv_sid_req) || + ipa3_delete_rtp_hdr_proc_rt_flt_rules(stream_id - 1)) { + IPADBG("Failed to remove stream id: %d filters from IPA and WLAN\n", stream_id); + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + return -EPERM; + } + + active_streams[stream_id - 1] = 0; + active_flt_cnt--; + IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); + IPADBG("Removed stream id: %d filters from IPA and WLAN\n", stream_id); + return count; +} +#endif + static const struct ipa3_debugfs_file debugfs_files[] = { { "gen_reg", IPA_READ_ONLY_MODE, NULL, { @@ -3777,6 +4265,24 @@ static const struct ipa3_debugfs_file debugfs_files[] = { "ipa_loopback_on_ipa", IPA_READ_ONLY_MODE, NULL, { .read = ipa3_perform_loopback, } + }, { + "xr_wlan_add_flt", IPA_WRITE_ONLY_MODE, NULL, { + .write = ipa_xr_add_flt_to_wlan + } + }, { + "xr_wlan_rmv_flt", IPA_WRITE_ONLY_MODE, NULL, { + .write = ipa_xr_remove_flt_to_wlan, + } +#if defined(CONFIG_IPA_RTP) + }, { + "xr_ipa_wlan_add_flt", IPA_WRITE_ONLY_MODE, NULL, { + .write = ipa_xr_add_flt_to_ipa_wlan, + } + }, { + "xr_ipa_wlan_rmv_flt", IPA_WRITE_ONLY_MODE, NULL, { + .write = ipa_xr_remove_flt_to_ipa_wlan, + } +#endif } }; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 7044e83cec..82cd0e99fb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -3863,5 +3863,6 @@ int ipa3_create_hfi_send_uc(void); int ipa3_allocate_uc_pipes_er_tr_send_to_uc(void); void ipa3_free_uc_temp_buffs(unsigned int no_of_buffs); void ipa3_free_uc_pipes_er_tr(void); +int ipa3_uc_send_add_bitstream_buffers_cmd(struct bitstream_buffers_to_uc *data); #endif #endif /* _IPA3_I_H_ */