From 7abd8fd06088b6271fa00ddecc6a13e1a55b7590 Mon Sep 17 00:00:00 2001 From: Chaitanya Pratapa Date: Sat, 17 Oct 2020 07:14:46 -0700 Subject: [PATCH] msm: ipa: Add new IOCTLs to get and set MTU Add a new IOCTL that will allow userspace modules to get and set the v4/v6 mtu for a specific rmnet interface for IPA driver and IPACM to use. Change-Id: Iaf0685ef7095960ddd1cd3fff803956a18e0a942 Signed-off-by: Chaitanya Pratapa Signed-off-by: Michael Adisumarta --- drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c | 1 + .../platform/msm/ipa/ipa_v3/ipa_qmi_service.h | 5 + drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c | 213 ++++++++++++++++++ .../msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c | 22 ++ 4 files changed, 241 insertions(+) diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c index c635d1cc5b15..ed234b69e82c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_debugfs.c @@ -75,6 +75,7 @@ const char *ipa3_event_name[IPA_EVENT_MAX_NUM] = { __stringify(IPA_GSB_DISCONNECT), __stringify(IPA_COALESCE_ENABLE), __stringify(IPA_COALESCE_DISABLE), + __stringify(IPA_SET_MTU), __stringify_1(WIGIG_CLIENT_CONNECT), __stringify_1(WIGIG_FST_SWITCH), }; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h index 46538945007a..ac3eec0ff7f0 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h @@ -121,6 +121,8 @@ struct ipa3_rmnet_mux_val { bool ul_flt_reg; bool mux_hdr_set; uint32_t hdr_hdl; + uint16_t mtu_v4; + uint16_t mtu_v6; }; extern struct qmi_elem_info @@ -305,6 +307,9 @@ int rmnet_ipa3_enable_per_client_stats(bool *data); int rmnet_ipa3_query_per_client_stats( struct wan_ioctl_query_per_client_stats *data); +int rmnet_ipa3_get_wan_mtu( + struct ipa_mtu_info *data); + int ipa3_qmi_get_data_stats(struct ipa_get_data_stats_req_msg_v01 *req, struct ipa_get_data_stats_resp_msg_v01 *resp); diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index 69d9656eb3a5..9668b7f3b1a3 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -90,6 +90,10 @@ static DECLARE_DELAYED_WORK(ipa_tether_stats_poll_wakequeue_work, static int rmnet_ipa_send_coalesce_notification(uint8_t qmap_id, bool enable, bool tcp, bool udp); +static int rmnet_ipa_send_set_mtu_notification(char *if_name, + uint16_t mtu_v4, uint16_t mtu_v6, enum ipa_ip_type ip); + + enum ipa3_wwan_device_status { WWAN_DEVICE_INACTIVE = 0, WWAN_DEVICE_ACTIVE = 1 @@ -1756,6 +1760,8 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) struct mutex *mux_mutex_ptr; int wan_ep; bool tcp_en = false, udp_en = false; + bool mtu_v4_set = false, mtu_v6_set = false; + enum ipa_ip_type iptype; IPAWANDBG("rmnet_ipa got ioctl number 0x%08x", cmd); switch (cmd) { @@ -2086,6 +2092,65 @@ static int ipa3_wwan_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) } mutex_unlock(&rmnet_ipa3_ctx->clock_vote.mutex); break; + /* Get MTU */ + case RMNET_IOCTL_GET_MTU: + mux_channel = rmnet_ipa3_ctx->mux_channel; + rmnet_index = + find_vchannel_name_index(ext_ioctl_data.u.mtu_params.if_name); + + if (rmnet_index == MAX_NUM_OF_MUX_CHANNEL) { + IPAWANERR("%s is an invalid iface name\n", + ext_ioctl_data.u.mtu_params.if_name); + return -ENODEV; + } + + IPAWANDBG("getting v4 MTU = %d\n", mux_channel[rmnet_index].mtu_v4); + ext_ioctl_data.u.mtu_params.mtu_v4 = + mux_channel[rmnet_index].mtu_v4; + + IPAWANDBG("getting v6 MTU = %d\n", mux_channel[rmnet_index].mtu_v6); + ext_ioctl_data.u.mtu_params.mtu_v6 = + mux_channel[rmnet_index].mtu_v6; + break; + /* Set MTU */ + case RMNET_IOCTL_SET_MTU: + mux_channel = rmnet_ipa3_ctx->mux_channel; + rmnet_index = + find_vchannel_name_index(ext_ioctl_data.u.mtu_params.if_name); + + if (rmnet_index == MAX_NUM_OF_MUX_CHANNEL) { + IPAWANERR("%s is an invalid iface name\n", + ext_ioctl_data.u.mtu_params.if_name); + return -ENODEV; + } + + /* V4 case */ + if (ext_ioctl_data.u.mtu_params.mtu_v4 > 0) { + mux_channel[rmnet_index].mtu_v4 = + ext_ioctl_data.u.mtu_params.mtu_v4; + mtu_v4_set = true; + IPAWANDBG("Set v4 MTU = %d\n", mux_channel[rmnet_index].mtu_v4); + iptype = IPA_IP_v4; + } + /* V6 case */ + if (ext_ioctl_data.u.mtu_params.mtu_v6 > 0) { + mux_channel[rmnet_index].mtu_v6 = + ext_ioctl_data.u.mtu_params.mtu_v6; + mtu_v6_set = true; + IPAWANDBG("Set v6 MTU = %d\n", mux_channel[rmnet_index].mtu_v6); + iptype = IPA_IP_v6; + } + + if (mtu_v4_set && mtu_v6_set) + iptype = IPA_IP_MAX; + + rc = rmnet_ipa_send_set_mtu_notification( + ext_ioctl_data.u.mtu_params.if_name, + mux_channel[rmnet_index].mtu_v4, + mux_channel[rmnet_index].mtu_v6, + iptype); + + break; default: IPAWANERR("[%s] unsupported extended cmd[%d]", dev->name, @@ -2179,6 +2244,37 @@ static int rmnet_ipa_send_coalesce_notification(uint8_t qmap_id, return 0; } +static int rmnet_ipa_send_set_mtu_notification(char *if_name, + uint16_t mtu_v4, uint16_t mtu_v6, enum ipa_ip_type ip) +{ + struct ipa_msg_meta msg_meta; + struct ipa_mtu_info *mtu_info; + int rc; + + memset(&msg_meta, 0, sizeof(struct ipa_msg_meta)); + mtu_info = kzalloc(sizeof(*mtu_info), GFP_KERNEL); + if (!mtu_info) + return -ENOMEM; + + strlcpy(mtu_info->if_name, if_name, IPA_RESOURCE_NAME_MAX); + mtu_info->mtu_v4 = mtu_v4; + mtu_info->mtu_v6 = mtu_v6; + mtu_info->ip_type = ip; + msg_meta.msg_type = IPA_SET_MTU; + msg_meta.msg_len = sizeof(struct ipa_mtu_info); + + rc = ipa_send_msg(&msg_meta, mtu_info, ipa3_wwan_msg_free_cb); + if (rc) { + IPAWANERR("ipa_send_msg failed: %d\n", rc); + return -EFAULT; + } + IPAWANDBG( + "sent new mtu_v4(%d)/mtu_v6(%d) with iptype(%d) for iface(%s) to IPACM", + mtu_v4, mtu_v6, ip, if_name); + + return 0; +} + int ipa3_wwan_set_modem_state(struct wan_ioctl_notify_wan_state *state) { uint32_t bw_mbps = 0; @@ -4785,13 +4881,118 @@ int rmnet_ipa3_query_per_client_stats( return 0; } +/* rmnet_ipa3_get_wan_mtu() - + * @data - IOCTL data + * + * This function handles WAN_IOC_GET_WAN_MTU. + * It is used to send WAN MTU information to IPACM. + * + * Return codes: + * 0: Success + * -EINVAL: Invalid args provided + */ +int rmnet_ipa3_get_wan_mtu( + struct ipa_mtu_info *data) +{ + struct ipa3_rmnet_mux_val *mux_channel; + int rmnet_index; + + mux_channel = rmnet_ipa3_ctx->mux_channel; + rmnet_index = + find_vchannel_name_index(data->if_name); + + if (rmnet_index == MAX_NUM_OF_MUX_CHANNEL) { + IPAWANERR("%s is an invalid iface name\n", + data->if_name); + return -ENODEV; + } + + IPAWANDBG("getting v4 MTU = %d\n", mux_channel[rmnet_index].mtu_v4); + data->mtu_v4 = + mux_channel[rmnet_index].mtu_v4; + + IPAWANDBG("getting v6 MTU = %d\n", mux_channel[rmnet_index].mtu_v6); + data->mtu_v6 = + mux_channel[rmnet_index].mtu_v6; + + return 0; +} #ifdef CONFIG_DEBUG_FS +static char dbg_buff[4096]; + +static ssize_t rmnet_ipa_set_mtu(struct file *file, + const char __user *buf, size_t count, loff_t *ppos) +{ + __s8 if_name[IFNAMSIZ]; + uint16_t mtu_v4 = 0, mtu_v6 = 0; + unsigned long missing; + char *sptr, *token; + + if (count >= sizeof(dbg_buff)) + return -EFAULT; + + missing = copy_from_user(dbg_buff, buf, count); + if (missing) + return -EFAULT; + + dbg_buff[count] = '\0'; + + sptr = dbg_buff; + + memset(if_name, 0, IFNAMSIZ); + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + strlcpy(if_name, token, IFNAMSIZ); + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &mtu_v4)) + return -EINVAL; + + token = strsep(&sptr, " "); + if (!token) + return -EINVAL; + if (kstrtou16(token, 0, &mtu_v6)) + return -EINVAL; + + rmnet_ipa_send_set_mtu_notification( + if_name, + mtu_v4, + mtu_v6, IPA_IP_MAX); + + return count; +} + + +#define RMNET_IPA_WRITE_ONLY_MODE 0220 + +struct rmnet_ipa_debugfs_file { + const char *name; + umode_t mode; + void *data; + const struct file_operations fops; +}; + +static const struct rmnet_ipa_debugfs_file debugfs_files[] = { + { + "mtu", RMNET_IPA_WRITE_ONLY_MODE, NULL, { + .write = rmnet_ipa_set_mtu, + } + }, +}; + static void rmnet_ipa_debugfs_init(void) { const mode_t read_write_mode = 0664; + int i = 0; + struct dentry *file; struct rmnet_ipa_debugfs *dbgfs = &rmnet_ipa3_ctx->dbgfs; + const size_t debugfs_files_num = + sizeof(debugfs_files) / sizeof(struct rmnet_ipa_debugfs_file); dbgfs->dent = debugfs_create_dir("rmnet_ipa", 0); @@ -4800,6 +5001,18 @@ static void rmnet_ipa_debugfs_init(void) return; } + for (i = 0; i < debugfs_files_num; ++i) { + const struct rmnet_ipa_debugfs_file *curr = &debugfs_files[i]; + + file = debugfs_create_file(curr->name, curr->mode, dbgfs->dent, + curr->data, &curr->fops); + if (!file || IS_ERR(file)) { + IPAERR("fail to create file for debug_fs %s\n", + curr->name); + goto fail; + } + } + dbgfs->dfile_outstanding_high = debugfs_create_u32("outstanding_high", read_write_mode, dbgfs->dent, &rmnet_ipa3_ctx->outstanding_high); diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c index 7c3f05135fb1..6a839241cd1c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa_fd_ioctl.c @@ -475,6 +475,28 @@ static long ipa3_wan_ioctl(struct file *filp, } break; + case WAN_IOC_GET_WAN_MTU: + IPAWANDBG_LOW("got WAN_IOC_GET_WAN_MTU :>>>\n"); + pyld_sz = sizeof(struct ipa_mtu_info); + param = memdup_user((const void __user *)arg, pyld_sz); + if (IS_ERR(param)) { + retval = PTR_ERR(param); + break; + } + if (rmnet_ipa3_get_wan_mtu( + (struct ipa_mtu_info *) + param)) { + IPAWANERR("WAN_IOC_GET_WAN_MTU failed\n"); + retval = -EFAULT; + break; + } + + if (copy_to_user((void __user *)arg, param, pyld_sz)) { + retval = -EFAULT; + break; + } + break; + default: retval = -ENOTTY; }