Эх сурвалжийг харах

dataipa: Add ipa_rtp generic netlink interface support

changes to enable ipa-rtp generic netlink for xr use-case to
receive all the commands from IPA Codec2 component in setting
up the control path of IPA HW RTP de-packetization for niobe.

Change-Id: I498204f7cd37675f24e9db6a10fd5668416ef45b
Signed-off-by: Jagadeesh Ponduru <[email protected]>
Jagadeesh Ponduru 1 жил өмнө
parent
commit
90e8adec6c

+ 6 - 0
define_modules.bzl

@@ -207,6 +207,12 @@ def define_modules(target, variant):
                     "drivers/platform/msm/ipa/test/ipa_test_ntn.c",
                 ],
             },
+            "CONFIG_ARCH_NIOBE": {
+                True: [
+                    "drivers/platform/msm/ipa/ipa_v3/ipa_rtp_genl.h",
+                    "drivers/platform/msm/ipa/ipa_v3/ipa_rtp_genl.c",
+                ],
+            },
         },
         local_defines = [
             "GSI_TRACE_INCLUDE_PATH={}/drivers/platform/msm/gsi".format(include_base),

+ 6 - 0
drivers/platform/msm/ipa/ipa_v3/ipa.c

@@ -12466,6 +12466,9 @@ static int __init ipa_module_init(void)
 		/* Register as a PCI device driver */
 		return pci_register_driver(&ipa_pci_driver);
 	}
+#ifdef CONFIG_IPA_RTP
+	ipa_rtp_genl_init();
+#endif
 
 	register_pm_notifier(&ipa_pm_notifier);
 	/* Register as a platform device driver */
@@ -12482,6 +12485,9 @@ static void __exit ipa_module_exit(void)
 		kfree(ipa3_ctx->hw_stats);
 		ipa3_ctx->hw_stats = NULL;
 	}
+#ifdef CONFIG_IPA_RTP
+	ipa_rtp_genl_deinit();
+#endif
 	unregister_pm_notifier(&ipa_pm_notifier);
 	kfree(ipa3_ctx);
 	ipa3_ctx = NULL;

+ 5 - 1
drivers/platform/msm/ipa/ipa_v3/ipa_i.h

@@ -2,7 +2,7 @@
 /*
  * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved.
  *
- * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _IPA3_I_H_
@@ -43,6 +43,9 @@
 #include <linux/rmnet_ipa_fd_ioctl.h>
 #include "ipa_uc_holb_monitor.h"
 #include <soc/qcom/minidump.h>
+#ifdef CONFIG_IPA_RTP
+#include "ipa_rtp_genl.h"
+#endif
 
 #define IPA_DEV_NAME_MAX_LEN 15
 #define DRV_NAME "ipa"
@@ -2423,6 +2426,7 @@ struct ipa3_context {
 	bool ipa_wdi2_over_gsi;
 	bool ipa_wdi3_over_gsi;
 	bool ipa_wdi_opt_dpath;
+	u8 rtp_stream_id_cnt;
 	bool ipa_endp_delay_wa;
 	bool lan_coal_enable;
 	bool ipa_fltrt_not_hashable;

+ 567 - 0
drivers/platform/msm/ipa/ipa_v3/ipa_rtp_genl.c

@@ -0,0 +1,567 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#include "ipa_rtp_genl.h"
+#include "ipa_i.h"
+#include <net/sock.h>
+#include <linux/skbuff.h>
+#include <uapi/linux/in.h>
+
+#define MAX_OPEN_FRAMES 3
+/* Single-NAL:0, FU-A Type: 1 */
+#define MAX_STREAM_TYPES 2
+#define MAX_IP_TYPES 2
+
+#define IPA_RTP_GENL_OP(_cmd, _func)			\
+	{						\
+		.cmd	= _cmd,				\
+		.doit	= _func,			\
+		.dumpit	= NULL,				\
+		.flags	= 0,				\
+	}
+
+static u8 si[MAX_STREAMS];
+
+static struct nla_policy ipa_rtp_genl_attr_policy[IPA_RTP_GENL_ATTR_MAX + 1] = {
+	[IPA_RTP_GENL_ATTR_STR]  = { .type = NLA_NUL_STRING, .len = IPA_RTP_GENL_MAX_STR_LEN },
+	[IPA_RTP_GENL_ATTR_INT]  = { .type = NLA_S32 },
+	[IPA_RTP_GENL_ATTR_TUPLE_INFO] = NLA_POLICY_EXACT_LEN(sizeof(struct traffic_tuple_info)),
+	[IPA_RTP_GENL_ATTR_ASSIGN_STREAM_ID] =
+				NLA_POLICY_EXACT_LEN(sizeof(struct assign_stream_id)),
+	[IPA_RTP_GENL_ATTR_ADD_BITSTREAM_BUFF] =
+				 NLA_POLICY_EXACT_LEN(sizeof(struct bitstream_buffers)),
+	[IPA_RTP_GENL_ATTR_SMMU_MAP_BUFF] = NLA_POLICY_EXACT_LEN(sizeof(struct map_buffer)),
+	[IPA_RTP_GENL_ATTR_SMMU_UNMAP_BUFF] = NLA_POLICY_EXACT_LEN(sizeof(struct unmap_buffer)),
+	[IPA_RTP_GENL_ATTR_REMOVE_STREAM_ID] =
+				 NLA_POLICY_EXACT_LEN(sizeof(struct remove_bitstream_buffers)),
+};
+
+static const struct genl_ops ipa_rtp_genl_ops[] = {
+	IPA_RTP_GENL_OP(IPA_RTP_GENL_CMD_TUPLE_INFO,
+			ipa_rtp_tuple_info_req_hdlr),
+	IPA_RTP_GENL_OP(IPA_RTP_GENL_CMD_ADD_BITSTREAM_BUFF,
+			ipa_rtp_add_bitstream_buff_req_hdlr),
+	IPA_RTP_GENL_OP(IPA_RTP_GENL_CMD_SMMU_MAP_BUFF,
+			ipa_rtp_smmu_map_buff_req_hdlr),
+	IPA_RTP_GENL_OP(IPA_RTP_GENL_CMD_SMMU_UNMAP_BUFF,
+			ipa_rtp_smmu_unmap_buff_req_hdlr),
+	IPA_RTP_GENL_OP(IPA_RTP_GENL_CMD_REMOVE_STREAM_ID,
+			ipa_rtp_rmv_stream_id_req_hdlr),
+};
+
+struct genl_family ipa_rtp_genl_family = {
+	.id = 0,
+	.hdrsize = 0,
+	.name    = IPA_RTP_GENL_FAMILY_NAME,
+	.version = IPA_RTP_GENL_VERSION,
+	.maxattr = IPA_RTP_GENL_ATTR_MAX,
+	.policy  = ipa_rtp_genl_attr_policy,
+	.ops     = ipa_rtp_genl_ops,
+	.n_ops   = ARRAY_SIZE(ipa_rtp_genl_ops),
+};
+
+int ipa_rtp_send_tuple_info_resp(struct genl_info *info,
+			      struct assign_stream_id *tuple_info_resp)
+{
+	struct sk_buff *skb;
+	void *msg_head;
+	int rc = -1;
+
+	IPADBG_LOW("Entry\n");
+
+	if (!info || !tuple_info_resp) {
+		IPAERR("Invalid params\n");
+		return rc;
+	}
+
+	skb = genlmsg_new(sizeof(struct assign_stream_id), GFP_KERNEL);
+	if (!skb) {
+		IPAERR("failed to alloc genmsg_new\n");
+		return rc;
+	}
+
+	msg_head = genlmsg_put(skb, 0, info->snd_seq + 1,
+			       &ipa_rtp_genl_family,
+			       0, IPA_RTP_GENL_CMD_ASSIGN_STREAM_ID);
+	if (!msg_head) {
+		IPAERR("failed at genlmsg_put\n");
+		goto free_skb;
+	}
+
+	rc = nla_put(skb, IPA_RTP_GENL_ATTR_ASSIGN_STREAM_ID,
+		     sizeof(struct assign_stream_id),
+		     tuple_info_resp);
+	if (rc != 0) {
+		IPAERR("failed at nla_put skb\n");
+		goto free_skb;
+	}
+
+	genlmsg_end(skb, msg_head);
+
+	rc = genlmsg_unicast(genl_info_net(info), skb, info->snd_portid);
+	if (rc != 0) {
+		IPAERR("failed in doing genlmsg_unicast\n");
+		goto free_skb;
+	}
+
+	ipa3_ctx->rtp_stream_id_cnt++;
+	IPADBG("assigned stream-id is %u\n", tuple_info_resp->stream_id);
+	IPADBG_LOW("Exit\n");
+
+free_skb:
+	kfree(skb);
+	return rc;
+}
+
+int ipa_rtp_tuple_info_req_hdlr(struct sk_buff *skb_2,
+				     struct genl_info *info)
+{
+	struct nlattr *na;
+	struct traffic_tuple_info tuple_info_req;
+	struct assign_stream_id tuple_info_resp;
+	int is_req_valid = 0, i = 0;
+	int stream_id_available = 0, rc = -1;
+
+	IPADBG("Entry\n");
+
+	if (!info) {
+		IPAERR("error genl info is null\n");
+		return rc;
+	}
+
+	na = info->attrs[IPA_RTP_GENL_ATTR_TUPLE_INFO];
+	if (na) {
+		if (nla_memcpy(&tuple_info_req, na,
+			       sizeof(tuple_info_req)) > 0) {
+			is_req_valid = 1;
+		} else {
+			IPAERR("nla_memcpy failed %d\n",
+			       IPA_RTP_GENL_ATTR_TUPLE_INFO);
+			return rc;
+		}
+	} else {
+		IPAERR("no info->attrs %d\n",
+		       IPA_RTP_GENL_ATTR_TUPLE_INFO);
+		return rc;
+	}
+
+	if (tuple_info_req.ts_info.no_of_openframe <= 0 ||
+		tuple_info_req.ts_info.no_of_openframe > MAX_OPEN_FRAMES ||
+		tuple_info_req.ts_info.stream_type >= MAX_STREAM_TYPES ||
+		!tuple_info_req.ts_info.max_pkt_frame ||
+		tuple_info_req.ip_type >= MAX_IP_TYPES) {
+		IPAERR("invalid no-of-open-frames %u or stream_type %u\n",
+				tuple_info_req.ts_info.no_of_openframe,
+				tuple_info_req.ts_info.stream_type);
+		IPAERR("or max_pkt_frames %u or ip_type %u params\n",
+				tuple_info_req.ts_info.max_pkt_frame,
+				tuple_info_req.ip_type);
+		return rc;
+	}
+
+	/* IPv4 Type */
+	if (!tuple_info_req.ip_type) {
+		if (tuple_info_req.ip_info.ipv4.protocol != IPPROTO_UDP ||
+			!tuple_info_req.ip_info.ipv4.src_ip ||
+			!tuple_info_req.ip_info.ipv4.dst_ip) {
+			IPAERR("invalid src_ip %u or dst_ip %u or protocol %u params\n",
+			tuple_info_req.ip_info.ipv4.src_ip, tuple_info_req.ip_info.ipv4.dst_ip,
+			tuple_info_req.ip_info.ipv4.protocol);
+			return rc;
+		}
+	} else {
+		if (tuple_info_req.ip_info.ipv6.protocol != IPPROTO_UDP) {
+			IPAERR("invalid ipv6 protocol %u params\n",
+				tuple_info_req.ip_info.ipv6.protocol);
+			return rc;
+		}
+	}
+
+	IPADBG_LOW("no_of_openframes are %u\n", tuple_info_req.ts_info.no_of_openframe);
+	IPADBG_LOW("max_pkt_frame is %u\n", tuple_info_req.ts_info.max_pkt_frame);
+	IPADBG_LOW("stream_type is %u\n", tuple_info_req.ts_info.stream_type);
+	IPADBG_LOW("reorder_timeout is %u\n", tuple_info_req.ts_info.reorder_timeout);
+	IPADBG_LOW("num_slices_per_frame are %u\n", tuple_info_req.ts_info.num_slices_per_frame);
+	IPADBG_LOW("ip_type is %u\n", tuple_info_req.ip_type);
+	IPADBG_LOW("src_port_number is %u\n", tuple_info_req.ip_info.ipv4.src_port_number);
+	IPADBG_LOW("dst_port_number is %u\n", tuple_info_req.ip_info.ipv4.dst_port_number);
+	IPADBG_LOW("src_ip is %u\n", tuple_info_req.ip_info.ipv4.src_ip);
+	IPADBG_LOW("dst_ip is %u\n", tuple_info_req.ip_info.ipv4.dst_ip);
+	IPADBG_LOW("protocol is %u\n", tuple_info_req.ip_info.ipv4.protocol);
+
+	/* Call IPA driver/uC tuple info API's here */
+	memset(&tuple_info_resp, 0, sizeof(tuple_info_resp));
+
+	for (i = 0; i < MAX_STREAMS; i++) {
+		if (si[i] == 0) {
+			tuple_info_resp.stream_id = i;
+			si[i] = 1;
+			stream_id_available = 1;
+			break;
+		}
+	}
+
+	if (!stream_id_available) {
+		IPAERR("max stream-ids supported are four only\n");
+		return rc;
+	}
+
+	if (is_req_valid &&
+		ipa_rtp_send_tuple_info_resp(info, &tuple_info_resp))
+		si[tuple_info_resp.stream_id] = 0;
+	else
+		rc = 0;
+
+	IPADBG("Exit\n");
+	return rc;
+}
+
+int ipa_rtp_smmu_map_buff_req_hdlr(struct sk_buff *skb_2,
+				     struct genl_info *info)
+{
+	struct nlattr *na;
+	struct map_buffer map_buffer_req;
+	int i = 0, is_req_valid = 0;
+	int rc = -1;
+
+	IPADBG("Entry\n");
+
+	if (!info) {
+		IPAERR("error genl info is null\n");
+		return rc;
+	}
+
+	na = info->attrs[IPA_RTP_GENL_ATTR_SMMU_MAP_BUFF];
+	if (na) {
+		if (nla_memcpy(&map_buffer_req, na,
+			       sizeof(map_buffer_req)) > 0) {
+			is_req_valid = 1;
+		} else {
+			IPAERR("nla_memcpy failed %d\n",
+			       IPA_RTP_GENL_ATTR_SMMU_MAP_BUFF);
+			return rc;
+		}
+	} else {
+		IPAERR("no info->attrs %d\n",
+		       IPA_RTP_GENL_ATTR_SMMU_MAP_BUFF);
+		return rc;
+	}
+
+	if (map_buffer_req.nfd <= 0 || map_buffer_req.nfd > MAX_FDS
+			 || map_buffer_req.stream_id > MAX_STREAMS) {
+		IPAERR("invalid nfd %u or stream_id %u params\n",
+					map_buffer_req.nfd, map_buffer_req.stream_id);
+		return rc;
+	}
+
+	IPADBG_LOW("number of fd's are %u\n", map_buffer_req.nfd);
+	IPADBG_LOW("stream_id is %u\n", map_buffer_req.stream_id);
+
+	/* If IPA C2 component is providing two fd's for meta fd and bitstream buff fd then
+	 * sizes need to be filled. If it is a single fd for both meta data and bitstream buff
+	 * then meta_buff_fd and bitstream_buffer_fd will be the same. And they need to fill
+	 * bitstream_buffer_size as actual size and meta_buff_size to zero.
+	 */
+
+	for (i = 0; i < map_buffer_req.nfd; i++) {
+		if (map_buffer_req.buff_info[i].bitstream_buffer_fd ==
+			map_buffer_req.buff_info[i].meta_buff_fd) {
+			if (!map_buffer_req.buff_info[i].bitstream_buffer_size ||
+				map_buffer_req.buff_info[i].meta_buff_size) {
+				IPAERR("invalid bitstream_buff_size %u\n",
+					map_buffer_req.buff_info[i].bitstream_buffer_size);
+				IPAERR("or meta_buff_size %u params\n",
+					map_buffer_req.buff_info[i].meta_buff_size);
+				return rc;
+			}
+		} else {
+			if (!map_buffer_req.buff_info[i].bitstream_buffer_size ||
+				!map_buffer_req.buff_info[i].meta_buff_size) {
+				IPAERR("invalid bitstream_buff_size %u\n",
+					map_buffer_req.buff_info[i].bitstream_buffer_size);
+				IPAERR("or meta_buff_size %u params\n",
+					map_buffer_req.buff_info[i].meta_buff_size);
+				return rc;
+			}
+		}
+
+		IPADBG_LOW("bitstream_buffer_fd is %u\n",
+			map_buffer_req.buff_info[i].bitstream_buffer_fd);
+		IPADBG_LOW("meta_buff_fd is %u\n",
+			map_buffer_req.buff_info[i].meta_buff_fd);
+		IPADBG_LOW("bitstream_buffer_size is %u\n",
+			map_buffer_req.buff_info[i].bitstream_buffer_size);
+		IPADBG_LOW("meta_buff_size is %u\n",
+			map_buffer_req.buff_info[i].meta_buff_size);
+	}
+
+	/* Call IPA driver/uC API's here */
+	if (is_req_valid)
+		rc = ipa3_map_buff_to_device_addr(&map_buffer_req);
+
+	IPADBG("Exit\n");
+	return rc;
+}
+
+int ipa_rtp_smmu_unmap_buff_req_hdlr(struct sk_buff *skb_2,
+				     struct genl_info *info)
+{
+	struct nlattr *na;
+	struct unmap_buffer unmap_buffer_req;
+	int i = 0, is_req_valid = 0, rc = -1;
+
+	IPADBG("Entry\n");
+
+	if (!info) {
+		IPAERR("error genl info is null\n");
+		return rc;
+	}
+
+	na = info->attrs[IPA_RTP_GENL_ATTR_SMMU_UNMAP_BUFF];
+	if (na) {
+		if (nla_memcpy(&unmap_buffer_req, na,
+			       sizeof(unmap_buffer_req)) > 0) {
+			is_req_valid = 1;
+		} else {
+			IPAERR("nla_memcpy failed %d\n",
+			       IPA_RTP_GENL_ATTR_SMMU_UNMAP_BUFF);
+			return rc;
+		}
+	} else {
+		IPAERR("no info->attrs %d\n",
+		       IPA_RTP_GENL_ATTR_SMMU_UNMAP_BUFF);
+		return rc;
+	}
+
+	if (unmap_buffer_req.nfd <= 0 || unmap_buffer_req.nfd > MAX_FDS
+				 || unmap_buffer_req.stream_id > MAX_STREAMS) {
+		IPAERR("invalid nfd %u or stream_id %u params\n",
+					unmap_buffer_req.nfd, unmap_buffer_req.stream_id);
+		return rc;
+	}
+
+	IPADBG_LOW("number of fd's are %u\n", unmap_buffer_req.nfd);
+	IPADBG_LOW("stream_id is %u\n", unmap_buffer_req.stream_id);
+
+	/* If IPA C2 component is providing two fd's for meta fd and bitstream buff fd then
+	 * sizes need to be filled. If it is a single fd for both meta data and bitstream buff
+	 * then meta_buff_fd and bitstream_buffer_fd will be the same. And they need to fill
+	 * bitstream_buffer_size as actual size and meta_buff_size to zero.
+	 */
+
+	for (i = 0; i < unmap_buffer_req.nfd; i++) {
+		if (unmap_buffer_req.buff_info[i].bitstream_buffer_fd ==
+			unmap_buffer_req.buff_info[i].meta_buff_fd) {
+			if (!unmap_buffer_req.buff_info[i].bitstream_buffer_size ||
+				unmap_buffer_req.buff_info[i].meta_buff_size) {
+				IPAERR("invalid bitstream_buff_size %u\n",
+					unmap_buffer_req.buff_info[i].bitstream_buffer_size);
+				IPAERR("or meta_buff_size %u params\n",
+					unmap_buffer_req.buff_info[i].meta_buff_size);
+				return rc;
+			}
+		} else {
+			if (!unmap_buffer_req.buff_info[i].bitstream_buffer_size ||
+				!unmap_buffer_req.buff_info[i].meta_buff_size) {
+				IPAERR("invalid bitstream_buff_size %u\n",
+					unmap_buffer_req.buff_info[i].bitstream_buffer_size);
+				IPAERR("or meta_buff_size %u params\n",
+					unmap_buffer_req.buff_info[i].meta_buff_size);
+				return rc;
+			}
+		}
+
+		IPADBG_LOW("bitstream_buffer_fd is %u\n",
+			unmap_buffer_req.buff_info[i].bitstream_buffer_fd);
+		IPADBG_LOW("meta_buff_fd is %u\n",
+			unmap_buffer_req.buff_info[i].meta_buff_fd);
+		IPADBG_LOW("bitstream_buffer_size is %u\n",
+			unmap_buffer_req.buff_info[i].bitstream_buffer_size);
+		IPADBG_LOW("meta_buff_size is %u\n",
+			unmap_buffer_req.buff_info[i].meta_buff_size);
+	}
+
+	/* Call IPA driver/uC tuple info API's here */
+	if (is_req_valid)
+		rc = ipa3_unmap_buff_from_device_addr(&unmap_buffer_req);
+
+	IPADBG("Exit\n");
+	return rc;
+}
+
+int ipa_rtp_add_bitstream_buff_req_hdlr(struct sk_buff *skb_2,
+				     struct genl_info *info)
+{
+	struct nlattr *na;
+	struct bitstream_buffers bs_buffer_req;
+	int i = 0, is_req_valid = 0, rc = -1;
+
+	IPADBG("Entry\n");
+
+	if (!info) {
+		IPAERR("error genl info is null\n");
+		return rc;
+	}
+
+	na = info->attrs[IPA_RTP_GENL_ATTR_ADD_BITSTREAM_BUFF];
+	if (na) {
+		if (nla_memcpy(&bs_buffer_req, na,
+			       sizeof(bs_buffer_req)) > 0) {
+			is_req_valid = 1;
+		} else {
+			IPAERR("nla_memcpy failed %d\n",
+			       IPA_RTP_GENL_ATTR_ADD_BITSTREAM_BUFF);
+			return rc;
+		}
+	} else {
+		IPAERR("no info->attrs %d\n",
+		       IPA_RTP_GENL_ATTR_ADD_BITSTREAM_BUFF);
+		return rc;
+	}
+
+	if (bs_buffer_req.buff_cnt <= 0 || bs_buffer_req.buff_cnt > MAX_BUFF ||
+				bs_buffer_req.cookie != IPA_BS_BUFF_COOKIE) {
+		IPAERR("invalid buff_cnt %u or buff_cookie 0x%x params\n",
+					bs_buffer_req.buff_cnt, bs_buffer_req.cookie);
+		return rc;
+	}
+
+	IPADBG_LOW("buff_cnt is %u\n", bs_buffer_req.buff_cnt);
+	IPADBG_LOW("cookie is 0x%x\n", bs_buffer_req.cookie);
+
+	/* If IPA C2 component is providing two buffers for meta data and bitstream buff,
+	 * they need to fill meta_buff_offset and buff_offset as zero.
+	 * If it is a single buffer for meta data and bitstream buff, then meta_buff_fd
+	 * and buff_fd will be the same. And they need to fill meta_buff_offset as zero
+	 * and fill the bitstream buff offset in buff_offset and it should be 4 byte aligned.
+	 */
+
+	for (i = 0; i < bs_buffer_req.buff_cnt; i++) {
+		if (bs_buffer_req.bs_info[i].stream_id >= MAX_STREAMS) {
+			IPAERR("invalid stream_id in buffer %u params\n",
+					bs_buffer_req.bs_info[i].stream_id);
+			return rc;
+		}
+
+		if (bs_buffer_req.bs_info[i].meta_buff_fd == bs_buffer_req.bs_info[i].buff_fd) {
+			if (bs_buffer_req.bs_info[i].meta_buff_offset ||
+				!bs_buffer_req.bs_info[i].buff_offset ||
+				bs_buffer_req.bs_info[i].meta_buff_size ||
+				!bs_buffer_req.bs_info[i].buff_size) {
+				IPAERR("invalid meta_buff_offset %u or bs_buff_offset %u\n",
+						bs_buffer_req.bs_info[i].meta_buff_offset,
+						bs_buffer_req.bs_info[i].buff_offset);
+				IPAERR("or meta_buff_size %u or bs_buff_size %u params\n",
+						bs_buffer_req.bs_info[i].meta_buff_size,
+						bs_buffer_req.bs_info[i].buff_size);
+				return rc;
+			}
+		} else {
+			if (bs_buffer_req.bs_info[i].meta_buff_offset ||
+				bs_buffer_req.bs_info[i].buff_offset ||
+				!bs_buffer_req.bs_info[i].meta_buff_size ||
+				!bs_buffer_req.bs_info[i].buff_size) {
+				IPAERR("invalid meta_buff_offset %u or bs_buff_offset %u\n",
+						bs_buffer_req.bs_info[i].meta_buff_offset,
+						bs_buffer_req.bs_info[i].buff_offset);
+				IPAERR("or meta_buff_size %u or bs_buff_size %u params\n",
+						bs_buffer_req.bs_info[i].meta_buff_size,
+						bs_buffer_req.bs_info[i].buff_size);
+				return rc;
+			}
+		}
+
+		IPADBG_LOW("stream_id is %u\n", bs_buffer_req.bs_info[i].stream_id);
+		IPADBG_LOW("fence_id is %u\n", bs_buffer_req.bs_info[i].fence_id);
+		IPADBG_LOW("buff_offset is %u\n", bs_buffer_req.bs_info[i].buff_offset);
+		IPADBG_LOW("buff_fd is %u\n", bs_buffer_req.bs_info[i].buff_fd);
+		IPADBG_LOW("buff_size is %u\n", bs_buffer_req.bs_info[i].buff_size);
+		IPADBG_LOW("meta_buff_offset is %u\n", bs_buffer_req.bs_info[i].meta_buff_offset);
+		IPADBG_LOW("meta_buff_fd is %u\n", bs_buffer_req.bs_info[i].meta_buff_fd);
+		IPADBG_LOW("meta_buff_size is %u\n", bs_buffer_req.bs_info[i].meta_buff_size);
+	}
+
+	/* Call IPA driver/uC API's here */
+	if (is_req_valid)
+		rc = ipa3_send_bitstream_buff_info(&bs_buffer_req);
+
+	IPADBG("Exit\n");
+	return rc;
+}
+
+int ipa_rtp_rmv_stream_id_req_hdlr(struct sk_buff *skb_2,
+				     struct genl_info *info)
+{
+	struct nlattr *na;
+	struct remove_bitstream_buffers rmv_sid_req;
+	int is_req_valid = 0, rc = -1;
+
+	IPADBG("Entry\n");
+
+	if (!info) {
+		IPAERR("error genl info is null\n");
+		return rc;
+	}
+
+	na = info->attrs[IPA_RTP_GENL_CMD_REMOVE_STREAM_ID];
+	if (na) {
+		if (nla_memcpy(&rmv_sid_req, na,
+			sizeof(rmv_sid_req)) > 0) {
+			is_req_valid = 1;
+		} else {
+			IPAERR("nla_memcpy failed %d\n",
+			       IPA_RTP_GENL_CMD_REMOVE_STREAM_ID);
+			return rc;
+		}
+	} else {
+		IPAERR("no info->attrs %d\n",
+		       IPA_RTP_GENL_CMD_REMOVE_STREAM_ID);
+		return rc;
+	}
+
+	if (rmv_sid_req.stream_id >= MAX_STREAMS) {
+		IPAERR("invalid stream_id %u params\n", rmv_sid_req.stream_id);
+		return rc;
+	}
+
+	/* Call IPA driver/uC tuple info API's here */
+	if (is_req_valid)
+		rc = ipa3_uc_send_remove_stream_cmd(&rmv_sid_req);
+
+	si[rmv_sid_req.stream_id] = 0;
+	ipa3_ctx->rtp_stream_id_cnt--;
+
+	IPADBG("Exit\n");
+	return rc;
+}
+
+/* register ipa rtp driver family with generic netlink */
+int ipa_rtp_genl_init(void)
+{
+	int rc = 0;
+
+	rc = genl_register_family(&ipa_rtp_genl_family);
+	if (rc != 0) {
+		IPAERR("ipa_rtp genl register family failed: %d", rc);
+		genl_unregister_family(&ipa_rtp_genl_family);
+		return rc;
+	}
+
+	IPAERR("successfully registered ipa_rtp genl family: %s",
+	       IPA_RTP_GENL_FAMILY_NAME);
+	return rc;
+}
+
+/* Unregister the generic netlink family */
+int ipa_rtp_genl_deinit(void)
+{
+	int rc = 0;
+
+	rc = genl_unregister_family(&ipa_rtp_genl_family);
+	if (rc != 0)
+		IPAERR("unregister ipa_rtp genl family failed: %d", rc);
+	return rc;
+}
+

+ 314 - 0
drivers/platform/msm/ipa/ipa_v3/ipa_rtp_genl.h

@@ -0,0 +1,314 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
+ */
+
+#ifndef _IPA_RTP_GENL_H_
+#define _IPA_RTP_GENL_H_
+
+#include <net/genetlink.h>
+
+/* Generic Netlink Definitions */
+#define IPA_RTP_GENL_VERSION 1
+#define IPA_RTP_GENL_FAMILY_NAME "ipa_rtp"
+
+#define IPA_RTP_GENL_MAX_STR_LEN 255
+#define MAX_BUFF 10
+#define MAX_FDS 10
+#define IPA_BS_BUFF_COOKIE 0x45670198
+
+/* XR IPAC2 <-> IPA Commands */
+
+/**
+ * struct buffer_info - buffer information of map and unmap buffers.
+ * @bitstream_buffer_fd: bit stream buffer file descriptor.
+ * @meta_buff_fd: meta buffer file descriptor.
+ * @bitstream_buffer_size: bit stream buffer fd size.
+ * @meta_buff_size: meta buffer fd size.
+ */
+
+struct buffer_info {
+	uint64_t bitstream_buffer_fd;
+	uint64_t meta_buff_fd;
+	uint64_t bitstream_buffer_size;
+	uint64_t meta_buff_size;
+};
+
+/**
+ * struct map_buffer - SMMU map buffers.
+ * @nfd: number of fd's.
+ * @stream_id: reciving stream ID.
+ * @buff_info: buffer information to map buffers.
+ */
+
+struct map_buffer {
+	uint32_t nfd;
+	uint32_t stream_id;
+	struct buffer_info buff_info[MAX_BUFF];
+};
+
+/**
+ * struct unmap_buffer - SMMU unmap buffers.
+ * @nfd: number of fd's.
+ * @stream_id: reciving stream ID.
+ * @buff_info: buffer information to unmap buffers.
+ */
+
+struct unmap_buffer {
+	uint32_t nfd;
+	uint32_t stream_id;
+	struct buffer_info buff_info[MAX_BUFF];
+};
+
+/**
+ * struct remove_bitstream_buffers - remove bitstream buffers.
+ * @stream_id: stream ID to stop using bitstream buffres of the specific stream.
+ */
+
+struct remove_bitstream_buffers {
+	uint32_t stream_id;
+};
+
+/**
+ * struct traffic_selector_info - traffic selector information.
+ * @no_of_openframe: no. of openframes in a stream.
+ * @max_pkt_frame: maximum packets per frame.
+ * @stream_type: type of stream.
+ * @reorder_timeout: RTP packets reordering timeout.
+ * @num_slices_per_frame: no. of slices per frame.
+ */
+
+struct traffic_selector_info {
+	uint32_t no_of_openframe;
+	uint32_t max_pkt_frame;
+	uint32_t stream_type;
+	uint64_t reorder_timeout;
+	uint32_t num_slices_per_frame;
+};
+
+/**
+ * struct ipv6_tuple_info - ipv6 tuple information.
+ * @src_port_number: source port number.
+ * @dst_port_number: dst port number.
+ * @src_ip: source IP.
+ * @dst_ip: dst IP.
+ * @protocol: protocol type.
+ */
+
+struct ipv6_tuple_info {
+	uint32_t src_port_number;
+	uint32_t dst_port_number;
+	uint8_t src_ip[16];
+	uint8_t dst_ip[16];
+	uint32_t protocol;
+};
+
+/**
+ * struct ipv4_tuple_info - ipv4 tuple information.
+ * @src_port_number: source port number.
+ * @dst_port_number: dst port number.
+ * @src_ip: source IP.
+ * @dst_ip: dst IP.
+ * @protocol: protocol type.
+ */
+
+struct ipv4_tuple_info {
+	uint32_t src_port_number;
+	uint32_t dst_port_number;
+	uint32_t src_ip;
+	uint32_t dst_ip;
+	uint32_t protocol;
+};
+
+/**
+ * struct ip_tuple_info - ip tuple information.
+ * @ipv4_tuple_info: ipv4 tuple information.
+ * @ipv6_tuple_info: ipv6 tuple information.
+ */
+
+union ip_tuple_info {
+	struct ipv4_tuple_info ipv4;
+	struct ipv6_tuple_info ipv6;
+};
+
+/**
+ * struct traffic_tuple_info - traffic tuple information.
+ * @ip_type: ip type (ipv4 or ipv6).
+ * @ip_tuple_info: ip tuple information.
+ */
+
+struct traffic_tuple_info {
+	struct traffic_selector_info ts_info;
+	uint8_t ip_type;
+	union ip_tuple_info ip_info;
+};
+
+/**
+ * struct assign_stream_id - assign stream id for a stream.
+ * @stream_id: assigned stream id.
+ */
+
+struct assign_stream_id {
+	uint32_t stream_id;
+};
+
+/**
+ * struct bitstream_buffer_info_to_ipa - bitstream buffer info to ipa.
+ * @stream_id: stream Identifier.
+ * @fence_id: fence Identifier.
+ * @buff_offset: bit stream buffer offset.
+ * @buff_fd: bit stream file descriptor.
+ * @buff_size: bit stream suffer size.
+ * @meta_buff_offset: bit stream metadata buffer offset.
+ * @meta_buff_fd: bit stream metadata buffer file descriptor.
+ * @meta_buff_size: bit stream metadata buffer size.
+ */
+
+struct bitstream_buffer_info_to_ipa {
+	uint32_t stream_id;
+	uint32_t fence_id;
+	uint32_t buff_offset;
+	uint32_t buff_fd;
+	uint32_t buff_size;
+	uint32_t meta_buff_offset;
+	uint32_t meta_buff_fd;
+	uint32_t meta_buff_size;
+};
+
+/**
+ * struct bitstream_buffers - bitstream buffers.
+ * @buff_cnt: number of buffers per stream.
+ * @cookie: pre-defined macro per stream.
+ * @bitstream_buffer_info_to_ipa: bitstream buffer info to ipa.
+ */
+
+struct bitstream_buffers {
+	uint32_t buff_cnt;
+	uint32_t cookie;
+	struct bitstream_buffer_info_to_ipa bs_info[MAX_BUFF];
+};
+
+/**
+ * struct bitstream_buffer_info_to_uspace - bitstream buffer info to IPA C2.
+ * @stream_id: stream Identifier.
+ * @fence_id: fence Identifier.
+ * @buff_offset: bit stream buffer offset.
+ * @buff_fd: bit stream file descriptor.
+ * @buff_size: bit stream suffer size.
+ * @meta_buff_offset: bit stream metadata buffer offset.
+ * @meta_buff_fd: bit stream metadata buffer file descriptor.
+ * @meta_buff_size: bit stream metadata buffer size.
+ * @reason_failure: reason for failure.
+ * @qtime_first_pkt_processed: qtime of first packet processed.
+ * @qtime_last_pkt_processed:  qtime of last packet processed.
+ */
+
+struct bitstream_buffer_info_to_uspace {
+	uint32_t frame_id;
+	uint32_t stream_id;
+	uint32_t fence_id;
+	uint64_t buff_offset;
+	uint32_t buff_fd;
+	uint32_t buff_size;
+	uint64_t meta_buff_offset;
+	uint32_t meta_buff_fd;
+	uint32_t meta_buff_size;
+	uint32_t reason_failure;
+	uint64_t qtime_first_pkt_processed;
+	uint64_t qtime_last_pkt_processed;
+};
+
+/**
+ * struct statistics_info - statistics information.
+ * @avg_reoder_latency: average reodering latency.
+ * @num_frame_to_sw: no. frames to sw-path.
+ * @last_frame_to_deco: last frame to decoder.
+ */
+
+struct statistics_info {
+	uint32_t avg_reoder_latency;
+	uint32_t num_frame_to_sw;
+	uint32_t last_frame_to_deco;
+};
+
+enum {
+	IPA_RTP_GENL_CMD_UNSPEC,
+	IPA_RTP_GENL_CMD_STR,
+	IPA_RTP_GENL_CMD_INT,
+	IPA_RTP_GENL_CMD_TUPLE_INFO,
+	IPA_RTP_GENL_CMD_ASSIGN_STREAM_ID,
+	IPA_RTP_GENL_CMD_ADD_BITSTREAM_BUFF,
+	IPA_RTP_GENL_CMD_SMMU_MAP_BUFF,
+	IPA_RTP_GENL_CMD_SMMU_UNMAP_BUFF,
+	IPA_RTP_GENL_CMD_REMOVE_STREAM_ID,
+	IPA_RTP_GENL_CMD_MAX,
+};
+
+enum {
+	IPA_RTP_GENL_ATTR_UNSPEC,
+	IPA_RTP_GENL_ATTR_STR,
+	IPA_RTP_GENL_ATTR_INT,
+	IPA_RTP_GENL_ATTR_TUPLE_INFO,
+	IPA_RTP_GENL_ATTR_ASSIGN_STREAM_ID,
+	IPA_RTP_GENL_ATTR_ADD_BITSTREAM_BUFF,
+	IPA_RTP_GENL_ATTR_SMMU_MAP_BUFF,
+	IPA_RTP_GENL_ATTR_SMMU_UNMAP_BUFF,
+	IPA_RTP_GENL_ATTR_REMOVE_STREAM_ID,
+	IPA_RTP_GENL_ATTR_MAX,
+};
+
+
+/* Function Prototypes */
+
+/*
+ * This handler will be invoked when IPA C2 sends TUPLE
+ * info cmd to IPA Driver via generic netlink interface.
+ */
+int ipa_rtp_tuple_info_req_hdlr(struct sk_buff *skb_2,
+				     struct genl_info *info);
+
+/*
+ * This function will be invoked when IPA driver allocates stream
+ * id and sends it to IPA C2 via generic netlink interface.
+ */
+int ipa_rtp_send_tuple_info_resp(struct genl_info *info,
+					 struct assign_stream_id *sid);
+
+/*
+ * This handler will be invoked when IPA C2 sends SMMU MAP
+ * info cmd to IPA Driver via generic netlink interface.
+ */
+int ipa_rtp_smmu_map_buff_req_hdlr(struct sk_buff *skb_2,
+				       struct genl_info *info);
+
+/*
+ * This handler will be invoked when IPA C2 sends SMMU UNMAP
+ * info cmd to IPA Driver via generic netlink interface.
+ */
+int ipa_rtp_smmu_unmap_buff_req_hdlr(struct sk_buff *skb_2,
+					 struct genl_info *info);
+
+/*
+ * This handler will be invoked when IPA C2 sends BITSTREAM BUFF
+ * info cmd to IPA Driver via generic netlink interface.
+ */
+int ipa_rtp_add_bitstream_buff_req_hdlr(struct sk_buff *skb_2,
+					 struct genl_info *info);
+
+/*
+ * This handler will be invoked when IPA C2 sends REMOVE STREAM
+ * info cmd to IPA Driver via generic netlink interface.
+ */
+int ipa_rtp_rmv_stream_id_req_hdlr(struct sk_buff *skb_2,
+					 struct genl_info *info);
+
+/*
+ * This is a generic netlink family init from IPA driver
+ * and when IPA C2 userspace comes, it will connect to this
+ * family via pre-defined name.
+ */
+int ipa_rtp_genl_init(void);
+
+int ipa_rtp_genl_deinit(void);
+
+#endif /*_IPA_RTP_GENL_H_*/