msm: ipa: Add IOCTL support to get ep_pair info
For QMI dpm port to open, control manager needs
to know about usb/mhi ep details corresponding to
RMNET and RMNET_CV2X tethering.
Ipa driver is the one has all ep info at one place.
So, provide IOCTL interface to get ep_pair info.
Change-Id: Ia5ec0df955ef7794ca992129dab538f65af36211
Signed-off-by: Mohammed Javid <mjavid@codeaurora.org>
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c
index 6de07dc..1537519 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c
@@ -624,6 +624,185 @@
kfree(buff);
}
+static void ipa3_get_usb_ep_info(
+ struct ipa_ioc_get_ep_info *ep_info,
+ struct ipa_ep_pair_info *pair_info
+ )
+{
+ int ep_index = -1, i;
+
+ ep_info->num_ep_pairs = 0;
+ for (i = 0; i < ep_info->max_ep_pairs; i++) {
+ pair_info[i].consumer_pipe_num = -1;
+ pair_info[i].producer_pipe_num = -1;
+ pair_info[i].ep_id = -1;
+ }
+
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB_PROD);
+
+ if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
+ pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB_CONS);
+ if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
+ pair_info[ep_info->num_ep_pairs].producer_pipe_num =
+ ep_index;
+ pair_info[ep_info->num_ep_pairs].ep_id =
+ IPA_USB0_EP_ID;
+
+ IPADBG("ep_pair_info consumer_pipe_num %d",
+ pair_info[ep_info->num_ep_pairs].
+ consumer_pipe_num);
+ IPADBG(" producer_pipe_num %d ep_id %d\n",
+ pair_info[ep_info->num_ep_pairs].
+ producer_pipe_num,
+ pair_info[ep_info->num_ep_pairs].ep_id);
+ ep_info->num_ep_pairs++;
+ } else {
+ pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
+ IPADBG("ep_pair_info consumer_pipe_num %d",
+ pair_info[ep_info->num_ep_pairs].
+ consumer_pipe_num);
+ IPADBG(" producer_pipe_num %d ep_id %d\n",
+ pair_info[ep_info->num_ep_pairs].
+ producer_pipe_num,
+ pair_info[ep_info->num_ep_pairs].ep_id);
+ }
+ }
+
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB2_PROD);
+
+ if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
+ pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_USB2_CONS);
+ if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
+ pair_info[ep_info->num_ep_pairs].producer_pipe_num =
+ ep_index;
+ pair_info[ep_info->num_ep_pairs].ep_id =
+ IPA_USB1_EP_ID;
+
+ IPADBG("ep_pair_info consumer_pipe_num %d",
+ pair_info[ep_info->num_ep_pairs].
+ consumer_pipe_num);
+ IPADBG(" producer_pipe_num %d ep_id %d\n",
+ pair_info[ep_info->num_ep_pairs].
+ producer_pipe_num,
+ pair_info[ep_info->num_ep_pairs].ep_id);
+ ep_info->num_ep_pairs++;
+ } else {
+ pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
+ IPADBG("ep_pair_info consumer_pipe_num %d",
+ pair_info[ep_info->num_ep_pairs].
+ consumer_pipe_num);
+ IPADBG(" producer_pipe_num %d ep_id %d\n",
+ pair_info[ep_info->num_ep_pairs].
+ producer_pipe_num,
+ pair_info[ep_info->num_ep_pairs].ep_id);
+ }
+ }
+}
+
+static void ipa3_get_pcie_ep_info(
+ struct ipa_ioc_get_ep_info *ep_info,
+ struct ipa_ep_pair_info *pair_info
+ )
+{
+ int ep_index = -1, i;
+
+ ep_info->num_ep_pairs = 0;
+ for (i = 0; i < ep_info->max_ep_pairs; i++) {
+ pair_info[i].consumer_pipe_num = -1;
+ pair_info[i].producer_pipe_num = -1;
+ pair_info[i].ep_id = -1;
+ }
+
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI_PROD);
+
+ if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
+ pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI_CONS);
+ if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
+ pair_info[ep_info->num_ep_pairs].producer_pipe_num =
+ ep_index;
+ pair_info[ep_info->num_ep_pairs].ep_id =
+ IPA_PCIE0_EP_ID;
+
+ IPADBG("ep_pair_info consumer_pipe_num %d",
+ pair_info[ep_info->num_ep_pairs].
+ consumer_pipe_num);
+ IPADBG(" producer_pipe_num %d ep_id %d\n",
+ pair_info[ep_info->num_ep_pairs].
+ producer_pipe_num,
+ pair_info[ep_info->num_ep_pairs].ep_id);
+ ep_info->num_ep_pairs++;
+ } else {
+ pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
+ IPADBG("ep_pair_info consumer_pipe_num %d",
+ pair_info[ep_info->num_ep_pairs].
+ consumer_pipe_num);
+ IPADBG(" producer_pipe_num %d ep_id %d\n",
+ pair_info[ep_info->num_ep_pairs].
+ producer_pipe_num,
+ pair_info[ep_info->num_ep_pairs].ep_id);
+ }
+ }
+
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI2_PROD);
+
+ if ((ep_index != -1) && ipa3_ctx->ep[ep_index].valid) {
+ pair_info[ep_info->num_ep_pairs].consumer_pipe_num = ep_index;
+ ep_index = ipa3_get_ep_mapping(IPA_CLIENT_MHI2_CONS);
+ if ((ep_index != -1) && (ipa3_ctx->ep[ep_index].valid)) {
+ pair_info[ep_info->num_ep_pairs].producer_pipe_num =
+ ep_index;
+ pair_info[ep_info->num_ep_pairs].ep_id =
+ IPA_PCIE1_EP_ID;
+
+ IPADBG("ep_pair_info consumer_pipe_num %d",
+ pair_info[ep_info->num_ep_pairs].
+ consumer_pipe_num);
+ IPADBG(" producer_pipe_num %d ep_id %d\n",
+ pair_info[ep_info->num_ep_pairs].
+ producer_pipe_num,
+ pair_info[ep_info->num_ep_pairs].ep_id);
+ ep_info->num_ep_pairs++;
+ } else {
+ pair_info[ep_info->num_ep_pairs].consumer_pipe_num = -1;
+ IPADBG("ep_pair_info consumer_pipe_num %d",
+ pair_info[ep_info->num_ep_pairs].
+ consumer_pipe_num);
+ IPADBG(" producer_pipe_num %d ep_id %d\n",
+ pair_info[ep_info->num_ep_pairs].
+ producer_pipe_num,
+ pair_info[ep_info->num_ep_pairs].ep_id);
+ }
+ }
+}
+
+
+static int ipa3_get_ep_info(struct ipa_ioc_get_ep_info *ep_info,
+ u8 *param)
+{
+ int ret = 0;
+ struct ipa_ep_pair_info *pair_info = (struct ipa_ep_pair_info *)param;
+
+ switch (ep_info->ep_type) {
+ case IPA_DATA_EP_TYP_HSUSB:
+ ipa3_get_usb_ep_info(ep_info, pair_info);
+ break;
+
+ case IPA_DATA_EP_TYP_PCIE:
+ ipa3_get_pcie_ep_info(ep_info, pair_info);
+ break;
+
+ default:
+ IPAERR_RL("Undefined ep_type %d\n", ep_info->ep_type);
+ ret = -EFAULT;
+ break;
+ }
+
+ return ret;
+}
+
static int ipa3_send_gsb_msg(unsigned long usr_param, uint8_t msg_type)
{
int retval;
@@ -689,8 +868,10 @@
struct ipa_ioc_rm_dependency rm_depend;
struct ipa_ioc_nat_dma_cmd *table_dma_cmd;
struct ipa_ioc_get_vlan_mode vlan_mode;
+ struct ipa_ioc_get_ep_info ep_info;
size_t sz;
int pre_entry;
+ unsigned long uptr = 0;
IPADBG("cmd=%x nr=%d\n", cmd, _IOC_NR(cmd));
@@ -1878,6 +2059,60 @@
}
break;
+ case IPA_IOC_GET_PHERIPHERAL_EP_INFO:
+ IPADBG("Got IPA_IOC_GET_EP_INFO\n");
+ if (copy_from_user(&ep_info, (const void __user *)arg,
+ sizeof(struct ipa_ioc_get_ep_info))) {
+ IPAERR_RL("copy_from_user fails\n");
+ retval = -EFAULT;
+ break;
+ }
+
+ if (ep_info.max_ep_pairs != QUERY_MAX_EP_PAIRS)
+ IPAERR_RL("unexpected max_ep_pairs %d\n",
+ ep_info.max_ep_pairs);
+
+ if (ep_info.ep_pair_size !=
+ (QUERY_MAX_EP_PAIRS * sizeof(struct ipa_ep_pair_info)))
+ IPAERR_RL("unexpected ep_pair_size %d\n",
+ ep_info.max_ep_pairs);
+
+ uptr = ep_info.info;
+ if (unlikely(!uptr)) {
+ IPAERR_RL("unexpected NULL info\n");
+ retval = -EFAULT;
+ break;
+ }
+
+ param = kzalloc(ep_info.ep_pair_size, GFP_KERNEL);
+ if (!param) {
+ IPAERR_RL("kzalloc fails\n");
+ retval = -ENOMEM;
+ break;
+ }
+
+ retval = ipa3_get_ep_info(&ep_info, param);
+ if (retval < 0) {
+ IPAERR("ipa3_get_ep_info failed\n");
+ retval = -EFAULT;
+ break;
+ }
+
+ if (copy_to_user((void __user *)uptr, param,
+ ep_info.ep_pair_size)) {
+ IPAERR_RL("copy_to_user fails\n");
+ retval = -EFAULT;
+ break;
+ }
+
+ if (copy_to_user((void __user *)arg, &ep_info,
+ sizeof(struct ipa_ioc_get_ep_info))) {
+ IPAERR_RL("copy_to_user fails\n");
+ retval = -EFAULT;
+ break;
+ }
+ break;
+
default:
IPA_ACTIVE_CLIENTS_DEC_SIMPLE();
return -ENOTTY;
diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h
index e64942a..3c810c2 100644
--- a/include/uapi/linux/msm_ipa.h
+++ b/include/uapi/linux/msm_ipa.h
@@ -107,7 +107,7 @@
#define IPA_IOCTL_DEL_BRIDGE_VLAN_MAPPING 60
#define IPA_IOCTL_GSB_CONNECT 61
#define IPA_IOCTL_GSB_DISCONNECT 62
-
+#define IPA_IOCTL_GET_PHERIPHERAL_EP_INFO 63
/**
@@ -1750,6 +1750,46 @@
char name[IPA_RESOURCE_NAME_MAX];
};
+#define QUERY_MAX_EP_PAIRS 2
+
+#define IPA_USB0_EP_ID 11
+#define IPA_USB1_EP_ID 12
+
+#define IPA_PCIE0_EP_ID 21
+#define IPA_PCIE1_EP_ID 22
+
+enum ipa_peripheral_ep_type {
+ IPA_DATA_EP_TYP_RESERVED = 0,
+ IPA_DATA_EP_TYP_HSIC = 1,
+ IPA_DATA_EP_TYP_HSUSB = 2,
+ IPA_DATA_EP_TYP_PCIE = 3,
+ IPA_DATA_EP_TYP_EMBEDDED = 4,
+ IPA_DATA_EP_TYP_BAM_DMUX,
+};
+
+struct ipa_ep_pair_info {
+ uint32_t consumer_pipe_num;
+ uint32_t producer_pipe_num;
+ uint32_t ep_id;
+};
+
+/**
+ * struct ipa_ioc_get_ep_info - flt/rt counter id query
+ * @ep_type: type USB/PCIE - i/p param
+ * @max_ep_pairs: max number of ep_pairs (constant),
+ (QUERY_MAX_EP_PAIRS)
+ * @num_ep_pairs: number of ep_pairs - o/p param
+ * @ep_pair_size: sizeof(ipa_ep_pair_info) * max_ep_pairs
+ * @info: structure contains ep pair info
+ */
+struct ipa_ioc_get_ep_info {
+ enum ipa_peripheral_ep_type ep_type;
+ uint8_t max_ep_pairs;
+ uint8_t num_ep_pairs;
+ uint32_t ep_pair_size;
+ uintptr_t info;
+};
+
/**
* struct ipa_msg_meta - Format of the message meta-data.
* @msg_type: the type of the message
@@ -2191,6 +2231,10 @@
IPA_IOCTL_GSB_DISCONNECT, \
struct ipa_ioc_gsb_info)
+#define IPA_IOC_GET_PHERIPHERAL_EP_INFO _IOWR(IPA_IOC_MAGIC, \
+ IPA_IOCTL_GET_PHERIPHERAL_EP_INFO, \
+ struct ipa_ioc_get_ep_info)
+
/*
* unique magic number of the Tethering bridge ioctls
*/