From: Skylar Chang Date: Sat, 7 Apr 2018 23:42:36 +0000 (-0700) Subject: msm: ipa: support ipacm cleanup X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=aef2c9f15c4ee1fab0fce00bf2be236d9051206c;p=sagit-ice-cold%2Fkernel_xiaomi_msm8998.git msm: ipa: support ipacm cleanup Support header/filter, routing rules cleanup when user-space module crashed like ipacm and also cached the wlan client connect messages for ipacm to query. Change-Id: Ib09cbe0e9114aa5a5673898ff796de7e7944af35 Acked-by: Pooja Kumari Signed-off-by: Mohammed Javid Signed-off-by: Skylar Chang --- diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 719a1ec5360f..66dd016e2132 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -340,13 +340,13 @@ int ipa_disconnect(u32 clnt_hdl) EXPORT_SYMBOL(ipa_disconnect); /** -* ipa_clear_endpoint_delay() - Clear ep_delay. -* @clnt_hdl: [in] IPA client handle -* -* Returns: 0 on success, negative on failure -* -* Note: Should not be called from atomic context -*/ + * ipa_clear_endpoint_delay() - Clear ep_delay. + * @clnt_hdl: [in] IPA client handle + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ int ipa_clear_endpoint_delay(u32 clnt_hdl) { int ret; @@ -358,13 +358,13 @@ int ipa_clear_endpoint_delay(u32 clnt_hdl) EXPORT_SYMBOL(ipa_clear_endpoint_delay); /** -* ipa_reset_endpoint() - reset an endpoint from BAM perspective -* @clnt_hdl: [in] IPA client handle -* -* Returns: 0 on success, negative on failure -* -* Note: Should not be called from atomic context -*/ + * ipa_reset_endpoint() - reset an endpoint from BAM perspective + * @clnt_hdl: [in] IPA client handle + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ int ipa_reset_endpoint(u32 clnt_hdl) { int ret; @@ -376,13 +376,13 @@ int ipa_reset_endpoint(u32 clnt_hdl) EXPORT_SYMBOL(ipa_reset_endpoint); /** -* ipa_disable_endpoint() - Disable an endpoint from IPA perspective -* @clnt_hdl: [in] IPA client handle -* -* Returns: 0 on success, negative on failure -* -* Note: Should not be called from atomic context -*/ + * ipa_disable_endpoint() - Disable an endpoint from IPA perspective + * @clnt_hdl: [in] IPA client handle + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ int ipa_disable_endpoint(u32 clnt_hdl) { int ret; @@ -676,8 +676,28 @@ int ipa_add_hdr(struct ipa_ioc_add_hdr *hdrs) EXPORT_SYMBOL(ipa_add_hdr); /** - * ipa_del_hdr() - Remove the specified headers from SW and optionally commit them - * to IPA HW + * ipa_add_hdr_usr() - add the specified headers to SW and optionally + * commit them to IPA HW + * @hdrs: [inout] set of headers to add + * @user_only: [in] indicate rules installed by userspace + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool user_only) +{ + int ret; + + IPA_API_DISPATCH_RETURN(ipa_add_hdr_usr, hdrs, user_only); + + return ret; +} +EXPORT_SYMBOL(ipa_add_hdr_usr); + +/** + * ipa_del_hdr() - Remove the specified headers from SW and optionally + * commit them to IPA HW * @hdls: [inout] set of headers to delete * * Returns: 0 on success, negative on failure @@ -715,15 +735,16 @@ EXPORT_SYMBOL(ipa_commit_hdr); * ipa_reset_hdr() - reset the current header table in SW (does not commit to * HW) * + * @user_only: [in] indicate delete rules installed by userspace * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa_reset_hdr(void) +int ipa_reset_hdr(bool user_only) { int ret; - IPA_API_DISPATCH_RETURN(ipa_reset_hdr); + IPA_API_DISPATCH_RETURN(ipa_reset_hdr, user_only); return ret; } @@ -793,16 +814,18 @@ EXPORT_SYMBOL(ipa_copy_hdr); * ipa_add_hdr_proc_ctx() - add the specified headers to SW * and optionally commit them to IPA HW * @proc_ctxs: [inout] set of processing context headers to add + * @user_only: [in] indicate rules installed by userspace * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) +int ipa_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs, + bool user_only) { int ret; - IPA_API_DISPATCH_RETURN(ipa_add_hdr_proc_ctx, proc_ctxs); + IPA_API_DISPATCH_RETURN(ipa_add_hdr_proc_ctx, proc_ctxs, user_only); return ret; } @@ -848,6 +871,26 @@ int ipa_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) EXPORT_SYMBOL(ipa_add_rt_rule); /** + * ipa_add_rt_rule_usr() - Add the specified routing rules to SW and optionally + * commit to IPA HW + * @rules: [inout] set of routing rules to add + * @user_only: [in] indicate rules installed by userspace + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, bool user_only) +{ + int ret; + + IPA_API_DISPATCH_RETURN(ipa_add_rt_rule_usr, rules, user_only); + + return ret; +} +EXPORT_SYMBOL(ipa_add_rt_rule_usr); + +/** * ipa_del_rt_rule() - Remove the specified routing rules to SW and optionally * commit to IPA HW * @hdls: [inout] set of routing rules to delete @@ -889,16 +932,17 @@ EXPORT_SYMBOL(ipa_commit_rt); * ipa_reset_rt() - reset the current SW routing table of specified type * (does not commit to HW) * @ip: The family of routing tables + * @user_only: [in] indicate delete rules installed by userspace * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa_reset_rt(enum ipa_ip_type ip) +int ipa_reset_rt(enum ipa_ip_type ip, bool user_only) { int ret; - IPA_API_DISPATCH_RETURN(ipa_reset_rt, ip); + IPA_API_DISPATCH_RETURN(ipa_reset_rt, ip, user_only); return ret; } @@ -981,6 +1025,7 @@ EXPORT_SYMBOL(ipa_mdfy_rt_rule); /** * ipa_add_flt_rule() - Add the specified filtering rules to SW and optionally * commit to IPA HW + * @rules: [inout] set of filtering rules to add * * Returns: 0 on success, negative on failure * @@ -997,6 +1042,26 @@ int ipa_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) EXPORT_SYMBOL(ipa_add_flt_rule); /** + * ipa_add_flt_rule_usr() - Add the specified filtering rules to + * SW and optionally commit to IPA HW + * @rules: [inout] set of filtering rules to add + * @user_only: [in] indicate rules installed by userspace + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, bool user_only) +{ + int ret; + + IPA_API_DISPATCH_RETURN(ipa_add_flt_rule_usr, rules, user_only); + + return ret; +} +EXPORT_SYMBOL(ipa_add_flt_rule_usr); + +/** * ipa_del_flt_rule() - Remove the specified filtering rules from SW and * optionally commit to IPA HW * @@ -1054,17 +1119,18 @@ EXPORT_SYMBOL(ipa_commit_flt); /** * ipa_reset_flt() - Reset the current SW filtering table of specified type * (does not commit to HW) - * @ip: [in] the family of routing tables + * @ip: [in] the family of routing tables + * @user_only: [in] indicate delete rules installed by userspace * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa_reset_flt(enum ipa_ip_type ip) +int ipa_reset_flt(enum ipa_ip_type ip, bool user_only) { int ret; - IPA_API_DISPATCH_RETURN(ipa_reset_flt, ip); + IPA_API_DISPATCH_RETURN(ipa_reset_flt, ip, user_only); return ret; } @@ -1710,20 +1776,20 @@ int ipa_uc_dereg_rdyCB(void) EXPORT_SYMBOL(ipa_uc_dereg_rdyCB); /** -* teth_bridge_init() - Initialize the Tethering bridge driver -* @params - in/out params for USB initialization API (please look at struct -* definition for more info) -* -* USB driver gets a pointer to a callback function (usb_notify_cb) and an -* associated data. USB driver installs this callback function in the call to -* ipa_connect(). -* -* Builds IPA resource manager dependency graph. -* -* Return codes: 0: success, -* -EINVAL - Bad parameter -* Other negative value - Failure -*/ + * teth_bridge_init() - Initialize the Tethering bridge driver + * @params - in/out params for USB initialization API (please look at struct + * definition for more info) + * + * USB driver gets a pointer to a callback function (usb_notify_cb) and an + * associated data. USB driver installs this callback function in the call to + * ipa_connect(). + * + * Builds IPA resource manager dependency graph. + * + * Return codes: 0: success, + * -EINVAL - Bad parameter + * Other negative value - Failure + */ int teth_bridge_init(struct teth_bridge_init_params *params) { int ret; @@ -1735,8 +1801,8 @@ int teth_bridge_init(struct teth_bridge_init_params *params) EXPORT_SYMBOL(teth_bridge_init); /** -* teth_bridge_disconnect() - Disconnect tethering bridge module -*/ + * teth_bridge_disconnect() - Disconnect tethering bridge module + */ int teth_bridge_disconnect(enum ipa_client_type client) { int ret; @@ -1748,14 +1814,14 @@ int teth_bridge_disconnect(enum ipa_client_type client) EXPORT_SYMBOL(teth_bridge_disconnect); /** -* teth_bridge_connect() - Connect bridge for a tethered Rmnet / MBIM call -* @connect_params: Connection info -* -* Return codes: 0: success -* -EINVAL: invalid parameters -* -EPERM: Operation not permitted as the bridge is already -* connected -*/ + * teth_bridge_connect() - Connect bridge for a tethered Rmnet / MBIM call + * @connect_params: Connection info + * + * Return codes: 0: success + * -EINVAL: invalid parameters + * -EPERM: Operation not permitted as the bridge is already + * connected + */ int teth_bridge_connect(struct teth_bridge_connect_params *connect_params) { int ret; @@ -2232,16 +2298,16 @@ int ipa_write_qmap_id(struct ipa_ioc_write_qmapid *param_in) EXPORT_SYMBOL(ipa_write_qmap_id); /** -* ipa_add_interrupt_handler() - Adds handler to an interrupt type -* @interrupt: Interrupt type -* @handler: The handler to be added -* @deferred_flag: whether the handler processing should be deferred in -* a workqueue -* @private_data: the client's private data -* -* Adds handler to an interrupt type and enable the specific bit -* in IRQ_EN register, associated interrupt in IRQ_STTS register will be enabled -*/ + * ipa_add_interrupt_handler() - Adds handler to an interrupt type + * @interrupt: Interrupt type + * @handler: The handler to be added + * @deferred_flag: whether the handler processing should be deferred in + * a workqueue + * @private_data: the client's private data + * + * Adds handler to an interrupt type and enable the specific bit + * in IRQ_EN register, associated interrupt in IRQ_STTS register will be enabled + */ int ipa_add_interrupt_handler(enum ipa_irq_type interrupt, ipa_irq_handler_t handler, bool deferred_flag, @@ -2257,11 +2323,11 @@ int ipa_add_interrupt_handler(enum ipa_irq_type interrupt, EXPORT_SYMBOL(ipa_add_interrupt_handler); /** -* ipa_remove_interrupt_handler() - Removes handler to an interrupt type -* @interrupt: Interrupt type -* -* Removes the handler and disable the specific bit in IRQ_EN register -*/ + * ipa_remove_interrupt_handler() - Removes handler to an interrupt type + * @interrupt: Interrupt type + * + * Removes the handler and disable the specific bit in IRQ_EN register + */ int ipa_remove_interrupt_handler(enum ipa_irq_type interrupt) { int ret; @@ -2273,12 +2339,12 @@ int ipa_remove_interrupt_handler(enum ipa_irq_type interrupt) EXPORT_SYMBOL(ipa_remove_interrupt_handler); /** -* ipa_restore_suspend_handler() - restores the original suspend IRQ handler -* as it was registered in the IPA init sequence. -* Return codes: -* 0: success -* -EPERM: failed to remove current handler or failed to add original handler -* */ + * ipa_restore_suspend_handler() - restores the original suspend IRQ handler + * as it was registered in the IPA init sequence. + * Return codes: + * 0: success + * -EPERM: failed to remove current handler or failed to add original handler + */ int ipa_restore_suspend_handler(void) { int ret; @@ -2621,10 +2687,10 @@ static int ipa_generic_plat_drv_probe(struct platform_device *pdev_p) { int result; - /* - * IPA probe function can be called for multiple times as the same probe - * function handles multiple compatibilities - */ +/** + * IPA probe function can be called for multiple times as the same probe + * function handles multiple compatibilities + */ pr_debug("ipa: IPA driver probing started for %s\n", pdev_p->dev.of_node->name); @@ -2747,7 +2813,7 @@ EXPORT_SYMBOL(ipa_register_ipa_ready_cb); * * Return codes: * None -*/ + */ void ipa_inc_client_enable_clks(struct ipa_active_client_logging_info *id) { IPA_API_DISPATCH(ipa_inc_client_enable_clks, id); @@ -2763,7 +2829,7 @@ EXPORT_SYMBOL(ipa_inc_client_enable_clks); * * Return codes: * None -*/ + */ void ipa_dec_client_disable_clks(struct ipa_active_client_logging_info *id) { IPA_API_DISPATCH(ipa_dec_client_disable_clks, id); @@ -2793,14 +2859,14 @@ int ipa_inc_client_enable_clks_no_block( EXPORT_SYMBOL(ipa_inc_client_enable_clks_no_block); /** -* ipa_suspend_resource_no_block() - suspend client endpoints related to the -* IPA_RM resource and decrement active clients counter. This function is -* guaranteed to avoid sleeping. -* -* @resource: [IN] IPA Resource Manager resource -* -* Return codes: 0 on success, negative on failure. -*/ + * ipa_suspend_resource_no_block() - suspend client endpoints related to the + * IPA_RM resource and decrement active clients counter. This function is + * guaranteed to avoid sleeping. + * + * @resource: [IN] IPA Resource Manager resource + * + * Return codes: 0 on success, negative on failure. + */ int ipa_suspend_resource_no_block(enum ipa_rm_resource_name resource) { int ret; diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h index 33e0f469d0d2..72db83c6e69d 100644 --- a/drivers/platform/msm/ipa/ipa_api.h +++ b/drivers/platform/msm/ipa/ipa_api.h @@ -69,11 +69,13 @@ struct ipa_api_controller { int (*ipa_add_hdr)(struct ipa_ioc_add_hdr *hdrs); + int (*ipa_add_hdr_usr)(struct ipa_ioc_add_hdr *hdrs, bool user_only); + int (*ipa_del_hdr)(struct ipa_ioc_del_hdr *hdls); int (*ipa_commit_hdr)(void); - int (*ipa_reset_hdr)(void); + int (*ipa_reset_hdr)(bool user_only); int (*ipa_get_hdr)(struct ipa_ioc_get_hdr *lookup); @@ -81,17 +83,21 @@ struct ipa_api_controller { int (*ipa_copy_hdr)(struct ipa_ioc_copy_hdr *copy); - int (*ipa_add_hdr_proc_ctx)(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs); + int (*ipa_add_hdr_proc_ctx)(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs, + bool user_only); int (*ipa_del_hdr_proc_ctx)(struct ipa_ioc_del_hdr_proc_ctx *hdls); int (*ipa_add_rt_rule)(struct ipa_ioc_add_rt_rule *rules); + int (*ipa_add_rt_rule_usr)(struct ipa_ioc_add_rt_rule *rules, + bool user_only); + int (*ipa_del_rt_rule)(struct ipa_ioc_del_rt_rule *hdls); int (*ipa_commit_rt)(enum ipa_ip_type ip); - int (*ipa_reset_rt)(enum ipa_ip_type ip); + int (*ipa_reset_rt)(enum ipa_ip_type ip, bool user_only); int (*ipa_get_rt_tbl)(struct ipa_ioc_get_rt_tbl *lookup); @@ -103,13 +109,16 @@ struct ipa_api_controller { int (*ipa_add_flt_rule)(struct ipa_ioc_add_flt_rule *rules); + int (*ipa_add_flt_rule_usr)(struct ipa_ioc_add_flt_rule *rules, + bool user_only); + int (*ipa_del_flt_rule)(struct ipa_ioc_del_flt_rule *hdls); int (*ipa_mdfy_flt_rule)(struct ipa_ioc_mdfy_flt_rule *rules); int (*ipa_commit_flt)(enum ipa_ip_type ip); - int (*ipa_reset_flt)(enum ipa_ip_type ip); + int (*ipa_reset_flt)(enum ipa_ip_type ip, bool user_only); int (*allocate_nat_device)(struct ipa_ioc_nat_alloc_mem *mem); diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h index 911db0b19079..00c3515bae30 100644 --- a/drivers/platform/msm/ipa/ipa_common_i.h +++ b/drivers/platform/msm/ipa/ipa_common_i.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -296,11 +296,13 @@ struct ipa_mhi_connect_params_internal { * @link: entry's link in global header offset entries list * @offset: the offset * @bin: bin + * @ipacm_installed: indicate if installed by ipacm */ struct ipa_hdr_offset_entry { struct list_head link; u32 offset; u32 bin; + bool ipacm_installed; }; extern const char *ipa_clients_strings[]; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa.c b/drivers/platform/msm/ipa/ipa_v2/ipa.c index bf46ea860fef..d9f8912c0514 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa.c @@ -279,6 +279,28 @@ int ipa2_active_clients_log_print_table(char *buf, int size) return cnt; } + +static int ipa2_clean_modem_rule(void) +{ + struct ipa_install_fltr_rule_req_msg_v01 *req; + int val = 0; + + req = kzalloc( + sizeof(struct ipa_install_fltr_rule_req_msg_v01), + GFP_KERNEL); + if (!req) { + IPAERR("mem allocated failed!\n"); + return -ENOMEM; + } + req->filter_spec_list_valid = false; + req->filter_spec_list_len = 0; + req->source_pipe_index_valid = 0; + val = qmi_filter_request_send(req); + kfree(req); + + return val; +} + static int ipa2_active_clients_panic_notifier(struct notifier_block *this, unsigned long event, void *ptr) { @@ -531,7 +553,8 @@ static void ipa_wan_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } -static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type, bool is_cache) +static int ipa_send_wan_msg(unsigned long usr_param, uint8_t msg_type, + bool is_cache) { int retval; struct ipa_wan_msg *wan_msg; @@ -716,7 +739,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - if (ipa2_add_hdr((struct ipa_ioc_add_hdr *)param)) { + if (ipa2_add_hdr_usr((struct ipa_ioc_add_hdr *)param, + true)) { retval = -EFAULT; break; } @@ -796,7 +820,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - if (ipa2_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) { + if (ipa2_add_rt_rule_usr((struct ipa_ioc_add_rt_rule *)param, + true)) { retval = -EFAULT; break; } @@ -915,7 +940,8 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - if (ipa2_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) { + if (ipa2_add_flt_rule_usr((struct ipa_ioc_add_flt_rule *)param, + true)) { retval = -EFAULT; break; } @@ -1009,19 +1035,19 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = ipa2_commit_hdr(); break; case IPA_IOC_RESET_HDR: - retval = ipa2_reset_hdr(); + retval = ipa2_reset_hdr(false); break; case IPA_IOC_COMMIT_RT: retval = ipa2_commit_rt(arg); break; case IPA_IOC_RESET_RT: - retval = ipa2_reset_rt(arg); + retval = ipa2_reset_rt(arg, false); break; case IPA_IOC_COMMIT_FLT: retval = ipa2_commit_flt(arg); break; case IPA_IOC_RESET_FLT: - retval = ipa2_reset_flt(arg); + retval = ipa2_reset_flt(arg, false); break; case IPA_IOC_GET_RT_TBL: if (copy_from_user(header, (u8 *)arg, @@ -1401,7 +1427,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } if (ipa2_add_hdr_proc_ctx( - (struct ipa_ioc_add_hdr_proc_ctx *)param)) { + (struct ipa_ioc_add_hdr_proc_ctx *)param, true)) { retval = -EFAULT; break; } @@ -1465,7 +1491,22 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; - default: /* redundant, as cmd was checked against MAXNR */ + case IPA_IOC_CLEANUP: + /*Route and filter rules will also be clean*/ + IPADBG("Got IPA_IOC_CLEANUP\n"); + retval = ipa2_reset_hdr(true); + memset(&nat_del, 0, sizeof(nat_del)); + nat_del.table_index = 0; + retval = ipa2_nat_del_cmd(&nat_del); + retval = ipa2_clean_modem_rule(); + break; + + case IPA_IOC_QUERY_WLAN_CLIENT: + IPADBG("Got IPA_IOC_QUERY_WLAN_CLIENT\n"); + retval = ipa2_resend_wlan_msg(); + break; + + default: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return -ENOTTY; } @@ -1478,7 +1519,7 @@ static long ipa_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) /** * ipa_setup_dflt_rt_tables() - Setup default routing tables -* + * Return codes: * 0: success * -ENOMEM: failed to allocate memory @@ -4301,6 +4342,10 @@ static int ipa_init(const struct ipa_plat_drv_res *resource_p, init_waitqueue_head(&ipa_ctx->msg_waitq); mutex_init(&ipa_ctx->msg_lock); + /* store wlan client-connect-msg-list */ + INIT_LIST_HEAD(&ipa_ctx->msg_wlan_client_list); + mutex_init(&ipa_ctx->msg_wlan_client_lock); + mutex_init(&ipa_ctx->lock); mutex_init(&ipa_ctx->nat_mem.lock); mutex_init(&ipa_ctx->ipa_cne_evt_lock); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c index 834f028d3e48..6392c379b026 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_flt.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1008,7 +1008,7 @@ fail_desc: static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip, const struct ipa_flt_rule *rule, u8 add_rear, - u32 *rule_hdl) + u32 *rule_hdl, bool user) { struct ipa_flt_entry *entry; struct ipa_rt_tbl *rt_tbl = NULL; @@ -1076,6 +1076,7 @@ static int __ipa_add_flt_rule(struct ipa_flt_tbl *tbl, enum ipa_ip_type ip, } *rule_hdl = id; entry->id = id; + entry->ipacm_installed = user; IPADBG_LOW("add flt rule rule_cnt=%d\n", tbl->rule_cnt); return 0; @@ -1198,12 +1199,12 @@ static int __ipa_add_global_flt_rule(enum ipa_ip_type ip, tbl = &ipa_ctx->glob_flt_tbl[ip]; IPADBG_LOW("add global flt rule ip=%d\n", ip); - return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl); + return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl, false); } static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, const struct ipa_flt_rule *rule, u8 add_rear, - u32 *rule_hdl) + u32 *rule_hdl, bool user) { struct ipa_flt_tbl *tbl; int ipa_ep_idx; @@ -1225,12 +1226,13 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][ip]; IPADBG_LOW("add ep flt rule ip=%d ep=%d\n", ip, ep); - return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl); + return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl, user); } /** * ipa2_add_flt_rule() - Add the specified filtering rules to SW and optionally * commit to IPA HW + * @rules: [inout] set of filtering rules to add * * Returns: 0 on success, negative on failure * @@ -1238,6 +1240,21 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, */ int ipa2_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) { + return ipa2_add_flt_rule_usr(rules, false); +} + +/** + * ipa2_add_flt_rule_usr() - Add the specified filtering rules + * to SW and optionally commit to IPA HW + * @rules: [inout] set of filtering rules to add + * @user_only: [in] indicate rules installed by userspace + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa2_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, bool user_only) +{ int i; int result; @@ -1259,7 +1276,8 @@ int ipa2_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) result = __ipa_add_ep_flt_rule(rules->ip, rules->ep, &rules->rules[i].rule, rules->rules[i].at_rear, - &rules->rules[i].flt_rule_hdl); + &rules->rules[i].flt_rule_hdl, + user_only); if (result) { IPAERR_RL("failed to add flt rule %d\n", i); rules->rules[i].status = IPA_FLT_STATUS_OF_ADD_FAILED; @@ -1396,13 +1414,14 @@ bail: /** * ipa2_reset_flt() - Reset the current SW filtering table of specified type * (does not commit to HW) - * @ip: [in] the family of routing tables + * @ip: [in] the family of routing tables + * @user_only: [in] indicate rules deleted by userspace * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa2_reset_flt(enum ipa_ip_type ip) +int ipa2_reset_flt(enum ipa_ip_type ip, bool user_only) { struct ipa_flt_tbl *tbl; struct ipa_flt_entry *entry; @@ -1435,16 +1454,19 @@ int ipa2_reset_flt(enum ipa_ip_type ip) IPA_INVALID_L4_PROTOCOL)) continue; - list_del(&entry->link); - entry->tbl->rule_cnt--; - if (entry->rt_tbl) - entry->rt_tbl->ref_cnt--; - entry->cookie = 0; - id = entry->id; - kmem_cache_free(ipa_ctx->flt_rule_cache, entry); + if (!user_only || + entry->ipacm_installed) { + list_del(&entry->link); + entry->tbl->rule_cnt--; + if (entry->rt_tbl) + entry->rt_tbl->ref_cnt--; + entry->cookie = 0; + id = entry->id; + kmem_cache_free(ipa_ctx->flt_rule_cache, entry); - /* remove the handle from the database */ - ipa_id_remove(id); + /* remove the handle from the database */ + ipa_id_remove(id); + } } for (i = 0; i < ipa_ctx->ipa_num_pipes; i++) { @@ -1456,16 +1478,21 @@ int ipa2_reset_flt(enum ipa_ip_type ip) mutex_unlock(&ipa_ctx->lock); return -EFAULT; } - list_del(&entry->link); - entry->tbl->rule_cnt--; - if (entry->rt_tbl) - entry->rt_tbl->ref_cnt--; - entry->cookie = 0; - id = entry->id; - kmem_cache_free(ipa_ctx->flt_rule_cache, entry); - /* remove the handle from the database */ - ipa_id_remove(id); + if (!user_only || + entry->ipacm_installed) { + list_del(&entry->link); + entry->tbl->rule_cnt--; + if (entry->rt_tbl) + entry->rt_tbl->ref_cnt--; + entry->cookie = 0; + id = entry->id; + kmem_cache_free(ipa_ctx->flt_rule_cache, + entry); + + /* remove the handle from the database */ + ipa_id_remove(id); + } } } mutex_unlock(&ipa_ctx->lock); @@ -1485,14 +1512,14 @@ void ipa_install_dflt_flt_rules(u32 ipa_ep_idx) tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4]; rule.action = IPA_PASS_TO_EXCEPTION; __ipa_add_flt_rule(tbl, IPA_IP_v4, &rule, true, - &ep->dflt_flt4_rule_hdl); + &ep->dflt_flt4_rule_hdl, false); ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v4); tbl->sticky_rear = true; tbl = &ipa_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6]; rule.action = IPA_PASS_TO_EXCEPTION; __ipa_add_flt_rule(tbl, IPA_IP_v6, &rule, true, - &ep->dflt_flt6_rule_hdl); + &ep->dflt_flt6_rule_hdl, false); ipa_ctx->ctrl->ipa_commit_flt(IPA_IP_v6); tbl->sticky_rear = true; mutex_unlock(&ipa_ctx->lock); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c index fbbb3f20b571..15c8f923d4f4 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_hdr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -543,7 +543,7 @@ int __ipa_commit_hdr_v2_6L(void) } static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, - bool add_ref_hdr) + bool add_ref_hdr, bool user_only) { struct ipa_hdr_entry *hdr_entry; struct ipa_hdr_proc_ctx_entry *entry; @@ -581,6 +581,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, if (add_ref_hdr) hdr_entry->ref_cnt++; entry->cookie = IPA_PROC_HDR_COOKIE; + entry->ipacm_installed = user_only; needed_len = (proc_ctx->type == IPA_HDR_PROC_NONE) ? sizeof(struct ipa_hdr_proc_ctx_add_hdr_seq) : @@ -619,6 +620,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, */ offset->offset = htbl->end; offset->bin = bin; + offset->ipacm_installed = user_only; htbl->end += ipa_hdr_proc_ctx_bin_sz[bin]; list_add(&offset->link, &htbl->head_offset_list[bin]); @@ -627,6 +629,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, offset = list_first_entry(&htbl->head_free_offset_list[bin], struct ipa_hdr_proc_ctx_offset_entry, link); + offset->ipacm_installed = user_only; list_move(&offset->link, &htbl->head_offset_list[bin]); } @@ -664,7 +667,7 @@ bad_len: } -static int __ipa_add_hdr(struct ipa_hdr_add *hdr) +static int __ipa_add_hdr(struct ipa_hdr_add *hdr, bool user) { struct ipa_hdr_entry *entry; struct ipa_hdr_offset_entry *offset = NULL; @@ -700,6 +703,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) entry->is_eth2_ofst_valid = hdr->is_eth2_ofst_valid; entry->eth2_ofst = hdr->eth2_ofst; entry->cookie = IPA_HDR_COOKIE; + entry->ipacm_installed = user; if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN0]) bin = IPA_HDR_BIN0; @@ -760,6 +764,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) list_add(&offset->link, &htbl->head_offset_list[bin]); entry->offset_entry = offset; + offset->ipacm_installed = user; } } else { entry->is_hdr_proc_ctx = false; @@ -769,6 +774,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) struct ipa_hdr_offset_entry, link); list_move(&offset->link, &htbl->head_offset_list[bin]); entry->offset_entry = offset; + offset->ipacm_installed = user; } list_add(&entry->link, &htbl->head_hdr_entry_list); @@ -800,7 +806,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) IPADBG("adding processing context for header %s\n", hdr->name); proc_ctx.type = IPA_HDR_PROC_NONE; proc_ctx.hdr_hdl = id; - if (__ipa_add_hdr_proc_ctx(&proc_ctx, false)) { + if (__ipa_add_hdr_proc_ctx(&proc_ctx, false, user)) { IPAERR("failed to add hdr proc ctx\n"); goto fail_add_proc_ctx; } @@ -960,6 +966,21 @@ int __ipa_del_hdr(u32 hdr_hdl, bool by_user) */ int ipa2_add_hdr(struct ipa_ioc_add_hdr *hdrs) { + return ipa2_add_hdr_usr(hdrs, false); +} + +/** + * ipa2_add_hdr_usr() - add the specified headers to SW + * and optionally commit them to IPA HW + * @hdrs: [inout] set of headers to add + * @user_only: [in] indicate installed from user + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa2_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool user_only) +{ int i; int result = -EFAULT; @@ -977,7 +998,7 @@ int ipa2_add_hdr(struct ipa_ioc_add_hdr *hdrs) IPADBG("adding %d headers to IPA driver internal data struct\n", hdrs->num_hdrs); for (i = 0; i < hdrs->num_hdrs; i++) { - if (__ipa_add_hdr(&hdrs->hdr[i])) { + if (__ipa_add_hdr(&hdrs->hdr[i], user_only)) { IPAERR_RL("failed to add hdr %d\n", i); hdrs->hdr[i].status = -1; } else { @@ -997,7 +1018,6 @@ bail: mutex_unlock(&ipa_ctx->lock); return result; } - /** * ipa2_del_hdr_by_user() - Remove the specified headers * from SW and optionally commit them to IPA HW @@ -1063,12 +1083,14 @@ int ipa2_del_hdr(struct ipa_ioc_del_hdr *hdls) * ipa2_add_hdr_proc_ctx() - add the specified headers to SW * and optionally commit them to IPA HW * @proc_ctxs: [inout] set of processing context headers to add + * @user_only: [in] indicate installed by user-space module * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) +int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs, + bool user_only) { int i; int result = -EFAULT; @@ -1089,7 +1111,8 @@ int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) IPADBG("adding %d header processing contextes to IPA driver\n", proc_ctxs->num_proc_ctxs); for (i = 0; i < proc_ctxs->num_proc_ctxs; i++) { - if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], true)) { + if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], + true, user_only)) { IPAERR_RL("failed to add hdr pric ctx %d\n", i); proc_ctxs->proc_ctx[i].status = -1; } else { @@ -1211,11 +1234,12 @@ bail: * ipa2_reset_hdr() - reset the current header table in SW (does not commit to * HW) * + * @user_only: [in] indicate delete rules installed by userspace * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa2_reset_hdr(void) +int ipa2_reset_hdr(bool user_only) { struct ipa_hdr_entry *entry; struct ipa_hdr_entry *next; @@ -1231,9 +1255,9 @@ int ipa2_reset_hdr(void) * issue a reset on the routing module since routing rules point to * header table entries */ - if (ipa2_reset_rt(IPA_IP_v4)) + if (ipa2_reset_rt(IPA_IP_v4, user_only)) IPAERR("fail to reset v4 rt\n"); - if (ipa2_reset_rt(IPA_IP_v6)) + if (ipa2_reset_rt(IPA_IP_v6, user_only)) IPAERR("fail to reset v4 rt\n"); mutex_lock(&ipa_ctx->lock); @@ -1262,21 +1286,23 @@ int ipa2_reset_hdr(void) WARN_ON(1); return -EFAULT; } - if (entry->is_hdr_proc_ctx) { - dma_unmap_single(ipa_ctx->pdev, - entry->phys_base, - entry->hdr_len, - DMA_TO_DEVICE); - entry->proc_ctx = NULL; - } - list_del(&entry->link); - entry->ref_cnt = 0; - entry->cookie = 0; - /* remove the handle from the database */ - ipa_id_remove(entry->id); - kmem_cache_free(ipa_ctx->hdr_cache, entry); + if (!user_only || entry->ipacm_installed) { + if (entry->is_hdr_proc_ctx) { + dma_unmap_single(ipa_ctx->pdev, + entry->phys_base, + entry->hdr_len, + DMA_TO_DEVICE); + entry->proc_ctx = NULL; + } + list_del(&entry->link); + entry->ref_cnt = 0; + entry->cookie = 0; + /* remove the handle from the database */ + ipa_id_remove(entry->id); + kmem_cache_free(ipa_ctx->hdr_cache, entry); + } } for (i = 0; i < IPA_HDR_BIN_MAX; i++) { list_for_each_entry_safe(off_entry, off_next, @@ -1290,14 +1316,23 @@ int ipa2_reset_hdr(void) if (off_entry->offset == 0) continue; - list_del(&off_entry->link); - kmem_cache_free(ipa_ctx->hdr_offset_cache, off_entry); + if (!user_only || + off_entry->ipacm_installed) { + list_del(&off_entry->link); + kmem_cache_free(ipa_ctx->hdr_offset_cache, + off_entry); + } } list_for_each_entry_safe(off_entry, off_next, &ipa_ctx->hdr_tbl.head_free_offset_list[i], link) { - list_del(&off_entry->link); - kmem_cache_free(ipa_ctx->hdr_offset_cache, off_entry); + + if (!user_only || + off_entry->ipacm_installed) { + list_del(&off_entry->link); + kmem_cache_free(ipa_ctx->hdr_offset_cache, + off_entry); + } } } /* there is one header of size 8 */ @@ -1316,30 +1351,43 @@ int ipa2_reset_hdr(void) WARN_ON(1); return -EFAULT; } - list_del(&ctx_entry->link); - ctx_entry->ref_cnt = 0; - ctx_entry->cookie = 0; - /* remove the handle from the database */ - ipa_id_remove(ctx_entry->id); - kmem_cache_free(ipa_ctx->hdr_proc_ctx_cache, ctx_entry); + if (!user_only || + ctx_entry->ipacm_installed) { + list_del(&ctx_entry->link); + ctx_entry->ref_cnt = 0; + ctx_entry->cookie = 0; + /* remove the handle from the database */ + ipa_id_remove(ctx_entry->id); + kmem_cache_free(ipa_ctx->hdr_proc_ctx_cache, + ctx_entry); + } } for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { list_for_each_entry_safe(ctx_off_entry, ctx_off_next, &ipa_ctx->hdr_proc_ctx_tbl.head_offset_list[i], link) { - list_del(&ctx_off_entry->link); - kmem_cache_free(ipa_ctx->hdr_proc_ctx_offset_cache, + if (!user_only || + ctx_off_entry->ipacm_installed) { + list_del(&ctx_off_entry->link); + kmem_cache_free( + ipa_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); + } } list_for_each_entry_safe(ctx_off_entry, ctx_off_next, &ipa_ctx->hdr_proc_ctx_tbl.head_free_offset_list[i], link) { - list_del(&ctx_off_entry->link); - kmem_cache_free(ipa_ctx->hdr_proc_ctx_offset_cache, - ctx_off_entry); + + if (!user_only || + ctx_off_entry->ipacm_installed) { + list_del(&ctx_off_entry->link); + kmem_cache_free( + ipa_ctx->hdr_proc_ctx_offset_cache, + ctx_off_entry); + } } } ipa_ctx->hdr_proc_ctx_tbl.end = 0; diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index 1986dc2af097..1d34564664bc 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -242,6 +242,8 @@ struct ipa_smmu_cb_ctx { * @tbl: filter table * @rt_tbl: routing table * @hw_len: entry's size + * @id: rule handle - globally unique + * @ipacm_installed: indicate if installed by ipacm */ struct ipa_flt_entry { struct list_head link; @@ -251,6 +253,7 @@ struct ipa_flt_entry { struct ipa_rt_tbl *rt_tbl; u32 hw_len; int id; + bool ipacm_installed; }; /** @@ -305,6 +308,7 @@ struct ipa_rt_tbl { * @is_eth2_ofst_valid: is eth2_ofst field valid? * @eth2_ofst: offset to start of Ethernet-II/802.3 header * @user_deleted: is the header deleted by the user? + * @ipacm_installed: indicate if installed by ipacm */ struct ipa_hdr_entry { struct list_head link; @@ -323,6 +327,7 @@ struct ipa_hdr_entry { u8 is_eth2_ofst_valid; u16 eth2_ofst; bool user_deleted; + bool ipacm_installed; }; /** @@ -346,11 +351,13 @@ struct ipa_hdr_tbl { * @link: entry's link in global processing context header offset entries list * @offset: the offset * @bin: bin + * @ipacm_installed: indicate if installed by ipacm */ struct ipa_hdr_proc_ctx_offset_entry { struct list_head link; u32 offset; u32 bin; + bool ipacm_installed; }; /** @@ -387,6 +394,7 @@ struct ipa_hdr_proc_ctx_add_hdr_cmd_seq { * @ref_cnt: reference counter of routing table * @id: processing context header entry id * @user_deleted: is the hdr processing context deleted by the user? + * @ipacm_installed: indicate if installed by ipacm */ struct ipa_hdr_proc_ctx_entry { struct list_head link; @@ -397,6 +405,7 @@ struct ipa_hdr_proc_ctx_entry { u32 ref_cnt; int id; bool user_deleted; + bool ipacm_installed; }; /** @@ -446,6 +455,8 @@ struct ipa_flt_tbl { * @hdr: header table * @proc_ctx: processing context table * @hw_len: the length of the table + * @id: rule handle - globaly unique + * @ipacm_installed: indicate if installed by ipacm */ struct ipa_rt_entry { struct list_head link; @@ -456,6 +467,7 @@ struct ipa_rt_entry { struct ipa_hdr_proc_ctx_entry *proc_ctx; u32 hw_len; int id; + bool ipacm_installed; }; /** @@ -1151,6 +1163,8 @@ struct ipa_context { struct list_head msg_list; struct list_head pull_msg_list; struct mutex msg_lock; + struct list_head msg_wlan_client_list; + struct mutex msg_wlan_client_lock; wait_queue_head_t msg_waitq; enum ipa_hw_type ipa_hw_type; enum ipa_hw_mode ipa_hw_mode; @@ -1441,13 +1455,15 @@ int ipa2_cfg_ep_ctrl(u32 clnt_hdl, const struct ipa_ep_cfg_ctrl *ep_ctrl); */ int ipa2_add_hdr(struct ipa_ioc_add_hdr *hdrs); +int ipa2_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool by_user); + int ipa2_del_hdr(struct ipa_ioc_del_hdr *hdls); int ipa2_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user); int ipa2_commit_hdr(void); -int ipa2_reset_hdr(void); +int ipa2_reset_hdr(bool user_only); int ipa2_get_hdr(struct ipa_ioc_get_hdr *lookup); @@ -1458,7 +1474,8 @@ int ipa2_copy_hdr(struct ipa_ioc_copy_hdr *copy); /* * Header Processing Context */ -int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs); +int ipa2_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs, + bool user_only); int ipa2_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls); @@ -1470,11 +1487,14 @@ int ipa2_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls, */ int ipa2_add_rt_rule(struct ipa_ioc_add_rt_rule *rules); +int ipa2_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, + bool user_only); + int ipa2_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls); int ipa2_commit_rt(enum ipa_ip_type ip); -int ipa2_reset_rt(enum ipa_ip_type ip); +int ipa2_reset_rt(enum ipa_ip_type ip, bool user_only); int ipa2_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup); @@ -1489,13 +1509,16 @@ int ipa2_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *rules); */ int ipa2_add_flt_rule(struct ipa_ioc_add_flt_rule *rules); +int ipa2_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, + bool user_only); + int ipa2_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls); int ipa2_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *rules); int ipa2_commit_flt(enum ipa_ip_type ip); -int ipa2_reset_flt(enum ipa_ip_type ip); +int ipa2_reset_flt(enum ipa_ip_type ip, bool user_only); /* * NAT @@ -1513,6 +1536,7 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del); */ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff, ipa_msg_free_fn callback); +int ipa2_resend_wlan_msg(void); int ipa2_register_pull_msg(struct ipa_msg_meta *meta, ipa_msg_pull_fn callback); int ipa2_deregister_pull_msg(struct ipa_msg_meta *meta); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c index 9c4fc0ce8cc1..da56a2ed1b8d 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,6 +13,7 @@ #include #include #include "ipa_i.h" +#include struct ipa_intf { char name[IPA_RESOURCE_NAME_MAX]; @@ -377,6 +378,108 @@ static void ipa2_send_msg_free(void *buff, u32 len, u32 type) kfree(buff); } +static int wlan_msg_process(struct ipa_msg_meta *meta, void *buff) +{ + struct ipa_push_msg *msg_dup; + struct ipa_wlan_msg_ex *event_ex_cur_con = NULL; + struct ipa_wlan_msg_ex *event_ex_list = NULL; + struct ipa_wlan_msg *event_ex_cur_discon = NULL; + void *data_dup = NULL; + struct ipa_push_msg *entry; + struct ipa_push_msg *next; + int cnt = 0, total = 0, max = 0; + uint8_t mac[IPA_MAC_ADDR_SIZE]; + uint8_t mac2[IPA_MAC_ADDR_SIZE]; + + if (meta->msg_type == WLAN_CLIENT_CONNECT_EX) { + /* debug print */ + event_ex_cur_con = buff; + for (cnt = 0; cnt < event_ex_cur_con->num_of_attribs; cnt++) { + if (event_ex_cur_con->attribs[cnt].attrib_type == + WLAN_HDR_ATTRIB_MAC_ADDR) { + IPADBG("%02x:%02x:%02x:%02x:%02x:%02x,(%d)\n", + event_ex_cur_con->attribs[cnt].u.mac_addr[0], + event_ex_cur_con->attribs[cnt].u.mac_addr[1], + event_ex_cur_con->attribs[cnt].u.mac_addr[2], + event_ex_cur_con->attribs[cnt].u.mac_addr[3], + event_ex_cur_con->attribs[cnt].u.mac_addr[4], + event_ex_cur_con->attribs[cnt].u.mac_addr[5], + meta->msg_type); + } + } + + mutex_lock(&ipa_ctx->msg_wlan_client_lock); + msg_dup = kzalloc(sizeof(struct ipa_push_msg), GFP_KERNEL); + if (msg_dup == NULL) { + IPAERR("fail to alloc ipa_msg container\n"); + return -ENOMEM; + } + msg_dup->meta = *meta; + if (meta->msg_len > 0 && buff) { + data_dup = kmalloc(meta->msg_len, GFP_KERNEL); + if (data_dup == NULL) { + IPAERR("fail to alloc data_dup container\n"); + kfree(msg_dup); + return -ENOMEM; + } + memcpy(data_dup, buff, meta->msg_len); + msg_dup->buff = data_dup; + msg_dup->callback = ipa2_send_msg_free; + } + list_add_tail(&msg_dup->link, &ipa_ctx->msg_wlan_client_list); + mutex_unlock(&ipa_ctx->msg_wlan_client_lock); + } + + /* remove the cache */ + if (meta->msg_type == WLAN_CLIENT_DISCONNECT) { + /* debug print */ + event_ex_cur_discon = buff; + IPADBG("Mac %02x:%02x:%02x:%02x:%02x:%02x,msg %d\n", + event_ex_cur_discon->mac_addr[0], + event_ex_cur_discon->mac_addr[1], + event_ex_cur_discon->mac_addr[2], + event_ex_cur_discon->mac_addr[3], + event_ex_cur_discon->mac_addr[4], + event_ex_cur_discon->mac_addr[5], + meta->msg_type); + memcpy(mac2, + event_ex_cur_discon->mac_addr, + sizeof(mac2)); + + mutex_lock(&ipa_ctx->msg_wlan_client_lock); + list_for_each_entry_safe(entry, next, + &ipa_ctx->msg_wlan_client_list, + link) { + event_ex_list = entry->buff; + max = event_ex_list->num_of_attribs; + for (cnt = 0; cnt < max; cnt++) { + memcpy(mac, + event_ex_list->attribs[cnt].u.mac_addr, + sizeof(mac)); + if (event_ex_list->attribs[cnt].attrib_type == + WLAN_HDR_ATTRIB_MAC_ADDR) { + pr_debug("%02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5]); + + /* compare to delete one*/ + if (memcmp(mac2, + mac, + sizeof(mac)) == 0) { + IPADBG("clean %d\n", total); + list_del(&entry->link); + kfree(entry); + break; + } + } + } + total++; + } + mutex_unlock(&ipa_ctx->msg_wlan_client_lock); + } + return 0; +} + /** * ipa2_send_msg() - Send "message" from kernel client to IPA driver * @meta: [in] message meta-data @@ -404,7 +507,7 @@ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff, } if (meta == NULL || (buff == NULL && callback != NULL) || - (buff != NULL && callback == NULL)) { + (buff != NULL && callback == NULL) || buff == NULL) { IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n", meta, buff, callback); return -EINVAL; @@ -436,6 +539,11 @@ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff, mutex_lock(&ipa_ctx->msg_lock); list_add_tail(&msg->link, &ipa_ctx->msg_list); + /* support for softap client event cache */ + if (wlan_msg_process(meta, buff)) + IPAERR("wlan_msg_process failed\n"); + + /* unlock only after process */ mutex_unlock(&ipa_ctx->msg_lock); IPA_STATS_INC_CNT(ipa_ctx->stats.msg_w[meta->msg_type]); @@ -447,6 +555,73 @@ int ipa2_send_msg(struct ipa_msg_meta *meta, void *buff, } /** + * ipa2_resend_wlan_msg() - Resend cached "message" to IPACM + * + * resend wlan client connect events to user-space + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa2_resend_wlan_msg(void) +{ + struct ipa_wlan_msg_ex *event_ex_list = NULL; + struct ipa_push_msg *entry; + struct ipa_push_msg *next; + int cnt = 0, total = 0; + struct ipa_push_msg *msg; + void *data = NULL; + + IPADBG("\n"); + + mutex_lock(&ipa_ctx->msg_wlan_client_lock); + list_for_each_entry_safe(entry, next, &ipa_ctx->msg_wlan_client_list, + link) { + + event_ex_list = entry->buff; + for (cnt = 0; cnt < event_ex_list->num_of_attribs; cnt++) { + if (event_ex_list->attribs[cnt].attrib_type == + WLAN_HDR_ATTRIB_MAC_ADDR) { + IPADBG("%d-Mac %02x:%02x:%02x:%02x:%02x:%02x\n", + total, + event_ex_list->attribs[cnt].u.mac_addr[0], + event_ex_list->attribs[cnt].u.mac_addr[1], + event_ex_list->attribs[cnt].u.mac_addr[2], + event_ex_list->attribs[cnt].u.mac_addr[3], + event_ex_list->attribs[cnt].u.mac_addr[4], + event_ex_list->attribs[cnt].u.mac_addr[5]); + } + } + + msg = kzalloc(sizeof(struct ipa_push_msg), GFP_KERNEL); + if (msg == NULL) { + IPAERR("fail to alloc ipa_msg container\n"); + mutex_unlock(&ipa_ctx->msg_wlan_client_lock); + return -ENOMEM; + } + msg->meta = entry->meta; + data = kmalloc(entry->meta.msg_len, GFP_KERNEL); + if (data == NULL) { + IPAERR("fail to alloc data container\n"); + kfree(msg); + mutex_unlock(&ipa_ctx->msg_wlan_client_lock); + return -ENOMEM; + } + memcpy(data, entry->buff, entry->meta.msg_len); + msg->buff = data; + msg->callback = ipa2_send_msg_free; + mutex_lock(&ipa_ctx->msg_lock); + list_add_tail(&msg->link, &ipa_ctx->msg_list); + mutex_unlock(&ipa_ctx->msg_lock); + wake_up(&ipa_ctx->msg_waitq); + + total++; + } + mutex_unlock(&ipa_ctx->msg_wlan_client_lock); + return 0; +} + +/** * ipa2_register_pull_msg() - register pull message type * @meta: [in] message meta-data * @callback: [in] pull callback diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c index 1be68b31656b..cc3d26764048 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_nat.c @@ -785,12 +785,6 @@ int ipa2_nat_del_cmd(struct ipa_ioc_v4_nat_del *del) base_addr = ipa_ctx->nat_mem.tmp_dma_handle; } - if (del->public_ip_addr == 0) { - IPADBG("Bad Parameter\n"); - result = -EPERM; - goto bail; - } - memset(&desc, 0, sizeof(desc)); /* NO-OP IC for ensuring that IPA pipeline is empty */ reg_write_nop = kzalloc(sizeof(*reg_write_nop), flag); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c index e33d0d86ac95..78555729d78a 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_qmi_service.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -514,6 +514,14 @@ int qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) int rc; int i; + /* check if modem up */ + if (!qmi_indication_fin || + !qmi_modem_init_fin || + !ipa_q6_clnt) { + IPAWANDBG("modem QMI haven't up yet\n"); + return -EINVAL; + } + /* check if the filter rules from IPACM is valid */ if (req->filter_spec_list_len == 0) { IPAWANDBG("IPACM pass zero rules to Q6\n"); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c index 7cc3c380ee71..e4a3a72ee670 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_rt.c @@ -1026,7 +1026,8 @@ static int __ipa_del_rt_tbl(struct ipa_rt_tbl *entry) } static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, - const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl) + const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl, + bool user) { struct ipa_rt_tbl *tbl; struct ipa_rt_entry *entry; @@ -1101,6 +1102,7 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, IPADBG_LOW("rule_cnt=%d\n", tbl->rule_cnt); *rule_hdl = id; entry->id = id; + entry->ipacm_installed = user; return 0; @@ -1126,6 +1128,21 @@ error: */ int ipa2_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) { + return ipa2_add_rt_rule_usr(rules, false); +} + +/** + * ipa2_add_rt_rule_usr() - Add the specified routing rules to SW and optionally + * commit to IPA HW + * @rules: [inout] set of routing rules to add + * @user_only: [in] indicate installed by userspace module + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa2_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, bool user_only) +{ int i; int ret; @@ -1139,7 +1156,8 @@ int ipa2_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) if (__ipa_add_rt_rule(rules->ip, rules->rt_tbl_name, &rules->rules[i].rule, rules->rules[i].at_rear, - &rules->rules[i].rt_rule_hdl)) { + &rules->rules[i].rt_rule_hdl, + user_only)) { IPAERR_RL("failed to add rt rule %d\n", i); rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED; } else { @@ -1308,13 +1326,14 @@ bail: /** * ipa2_reset_rt() - reset the current SW routing table of specified type * (does not commit to HW) - * @ip: The family of routing tables + * @ip: [in] The family of routing tables + * @user_only: [in] indicate delete rules installed by userspace * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa2_reset_rt(enum ipa_ip_type ip) +int ipa2_reset_rt(enum ipa_ip_type ip, bool user_only) { struct ipa_rt_tbl *tbl; struct ipa_rt_tbl *tbl_next; @@ -1324,6 +1343,7 @@ int ipa2_reset_rt(enum ipa_ip_type ip) struct ipa_rt_tbl_set *rset; u32 apps_start_idx; int id; + bool tbl_user = false; if (ip >= IPA_IP_MAX) { IPAERR_RL("bad parm\n"); @@ -1343,7 +1363,7 @@ int ipa2_reset_rt(enum ipa_ip_type ip) * issue a reset on the filtering module of same IP type since * filtering rules point to routing tables */ - if (ipa2_reset_flt(ip)) + if (ipa2_reset_flt(ip, user_only)) IPAERR_RL("fail to reset flt ip=%d\n", ip); set = &ipa_ctx->rt_tbl_set[ip]; @@ -1351,6 +1371,7 @@ int ipa2_reset_rt(enum ipa_ip_type ip) mutex_lock(&ipa_ctx->lock); IPADBG("reset rt ip=%d\n", ip); list_for_each_entry_safe(tbl, tbl_next, &set->head_rt_tbl_list, link) { + tbl_user = false; list_for_each_entry_safe(rule, rule_next, &tbl->head_rt_rule_list, link) { if (ipa_id_find(rule->id) == NULL) { @@ -1359,25 +1380,34 @@ int ipa2_reset_rt(enum ipa_ip_type ip) return -EFAULT; } + /* indicate if tbl used for user-specified rules*/ + if (rule->ipacm_installed) { + IPADBG("tbl_user %d, tbl-index %d\n", + tbl_user, tbl->id); + tbl_user = true; + } /* * for the "default" routing tbl, remove all but the * last rule */ if (tbl->idx == apps_start_idx && tbl->rule_cnt == 1) continue; - - list_del(&rule->link); - tbl->rule_cnt--; - if (rule->hdr) - __ipa_release_hdr(rule->hdr->id); - else if (rule->proc_ctx) - __ipa_release_hdr_proc_ctx(rule->proc_ctx->id); - rule->cookie = 0; - id = rule->id; - kmem_cache_free(ipa_ctx->rt_rule_cache, rule); - - /* remove the handle from the database */ - ipa_id_remove(id); + if (!user_only || + rule->ipacm_installed) { + list_del(&rule->link); + tbl->rule_cnt--; + if (rule->hdr) + __ipa_release_hdr(rule->hdr->id); + else if (rule->proc_ctx) + __ipa_release_hdr_proc_ctx( + rule->proc_ctx->id); + rule->cookie = 0; + id = rule->id; + kmem_cache_free(ipa_ctx->rt_rule_cache, rule); + + /* remove the handle from the database */ + ipa_id_remove(id); + } } if (ipa_id_find(tbl->id) == NULL) { @@ -1389,24 +1419,28 @@ int ipa2_reset_rt(enum ipa_ip_type ip) /* do not remove the "default" routing tbl which has index 0 */ if (tbl->idx != apps_start_idx) { - if (!tbl->in_sys) { - list_del(&tbl->link); - set->tbl_cnt--; - clear_bit(tbl->idx, - &ipa_ctx->rt_idx_bitmap[ip]); - IPADBG("rst rt tbl_idx=%d tbl_cnt=%d\n", - tbl->idx, set->tbl_cnt); - kmem_cache_free(ipa_ctx->rt_tbl_cache, tbl); - } else { - list_move(&tbl->link, &rset->head_rt_tbl_list); - clear_bit(tbl->idx, - &ipa_ctx->rt_idx_bitmap[ip]); - set->tbl_cnt--; - IPADBG("rst sys rt tbl_idx=%d tbl_cnt=%d\n", - tbl->idx, set->tbl_cnt); + if (!user_only || tbl_user) { + if (!tbl->in_sys) { + list_del(&tbl->link); + set->tbl_cnt--; + clear_bit(tbl->idx, + &ipa_ctx->rt_idx_bitmap[ip]); + IPADBG("rst rt tbl_idx=%d tbl_cnt=%d\n", + tbl->idx, set->tbl_cnt); + kmem_cache_free(ipa_ctx->rt_tbl_cache, + tbl); + } else { + list_move(&tbl->link, + &rset->head_rt_tbl_list); + clear_bit(tbl->idx, + &ipa_ctx->rt_idx_bitmap[ip]); + set->tbl_cnt--; + IPADBG("rst tbl_idx=%d cnt=%d\n", + tbl->idx, set->tbl_cnt); + } + /* remove the handle from the database */ + ipa_id_remove(id); } - /* remove the handle from the database */ - ipa_id_remove(id); } } mutex_unlock(&ipa_ctx->lock); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index 76f74c058c6d..f8d6e68a0d78 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -5078,6 +5078,7 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_cfg_ep_holb_by_client = ipa2_cfg_ep_holb_by_client; api_ctrl->ipa_cfg_ep_ctrl = ipa2_cfg_ep_ctrl; api_ctrl->ipa_add_hdr = ipa2_add_hdr; + api_ctrl->ipa_add_hdr_usr = ipa2_add_hdr_usr; api_ctrl->ipa_del_hdr = ipa2_del_hdr; api_ctrl->ipa_commit_hdr = ipa2_commit_hdr; api_ctrl->ipa_reset_hdr = ipa2_reset_hdr; @@ -5087,6 +5088,7 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_add_hdr_proc_ctx = ipa2_add_hdr_proc_ctx; api_ctrl->ipa_del_hdr_proc_ctx = ipa2_del_hdr_proc_ctx; api_ctrl->ipa_add_rt_rule = ipa2_add_rt_rule; + api_ctrl->ipa_add_rt_rule_usr = ipa2_add_rt_rule_usr; api_ctrl->ipa_del_rt_rule = ipa2_del_rt_rule; api_ctrl->ipa_commit_rt = ipa2_commit_rt; api_ctrl->ipa_reset_rt = ipa2_reset_rt; @@ -5095,6 +5097,7 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_query_rt_index = ipa2_query_rt_index; api_ctrl->ipa_mdfy_rt_rule = ipa2_mdfy_rt_rule; api_ctrl->ipa_add_flt_rule = ipa2_add_flt_rule; + api_ctrl->ipa_add_flt_rule_usr = ipa2_add_flt_rule_usr; api_ctrl->ipa_del_flt_rule = ipa2_del_flt_rule; api_ctrl->ipa_mdfy_flt_rule = ipa2_mdfy_flt_rule; api_ctrl->ipa_commit_flt = ipa2_commit_flt; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa.c b/drivers/platform/msm/ipa/ipa_v3/ipa.c index 681b2d945945..dfff3b422659 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa.c @@ -345,6 +345,43 @@ int ipa3_active_clients_log_print_table(char *buf, int size) return cnt; } +static int ipa3_clean_modem_rule(void) +{ + struct ipa_install_fltr_rule_req_msg_v01 *req; + struct ipa_install_fltr_rule_req_ex_msg_v01 *req_ex; + int val = 0; + + if (ipa3_ctx->ipa_hw_type < IPA_HW_v3_0) { + req = kzalloc( + sizeof(struct ipa_install_fltr_rule_req_msg_v01), + GFP_KERNEL); + if (!req) { + IPAERR("mem allocated failed!\n"); + return -ENOMEM; + } + req->filter_spec_list_valid = false; + req->filter_spec_list_len = 0; + req->source_pipe_index_valid = 0; + val = ipa3_qmi_filter_request_send(req); + kfree(req); + } else { + req_ex = kzalloc( + sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01), + GFP_KERNEL); + if (!req_ex) { + IPAERR("mem allocated failed!\n"); + return -ENOMEM; + } + req_ex->filter_spec_ex_list_valid = false; + req_ex->filter_spec_ex_list_len = 0; + req_ex->source_pipe_index_valid = 0; + val = ipa3_qmi_filter_request_ex_send(req_ex); + kfree(req_ex); + } + + return val; +} + static int ipa3_active_clients_panic_notifier(struct notifier_block *this, unsigned long event, void *ptr) { @@ -598,7 +635,8 @@ static void ipa3_wan_msg_free_cb(void *buff, u32 len, u32 type) kfree(buff); } -static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type, bool is_cache) +static int ipa3_send_wan_msg(unsigned long usr_param, uint8_t msg_type, + bool is_cache) { int retval; struct ipa_wan_msg *wan_msg; @@ -906,7 +944,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - if (ipa3_add_hdr((struct ipa_ioc_add_hdr *)param)) { + if (ipa3_add_hdr_usr((struct ipa_ioc_add_hdr *)param, + true)) { retval = -EFAULT; break; } @@ -986,7 +1025,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - if (ipa3_add_rt_rule((struct ipa_ioc_add_rt_rule *)param)) { + if (ipa3_add_rt_rule_usr((struct ipa_ioc_add_rt_rule *)param, + true)) { retval = -EFAULT; break; } @@ -1191,7 +1231,8 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = -EFAULT; break; } - if (ipa3_add_flt_rule((struct ipa_ioc_add_flt_rule *)param)) { + if (ipa3_add_flt_rule_usr((struct ipa_ioc_add_flt_rule *)param, + true)) { retval = -EFAULT; break; } @@ -1328,19 +1369,19 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) retval = ipa3_commit_hdr(); break; case IPA_IOC_RESET_HDR: - retval = ipa3_reset_hdr(); + retval = ipa3_reset_hdr(false); break; case IPA_IOC_COMMIT_RT: retval = ipa3_commit_rt(arg); break; case IPA_IOC_RESET_RT: - retval = ipa3_reset_rt(arg); + retval = ipa3_reset_rt(arg, false); break; case IPA_IOC_COMMIT_FLT: retval = ipa3_commit_flt(arg); break; case IPA_IOC_RESET_FLT: - retval = ipa3_reset_flt(arg); + retval = ipa3_reset_flt(arg, false); break; case IPA_IOC_GET_RT_TBL: if (copy_from_user(header, (u8 *)arg, @@ -1720,7 +1761,7 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) break; } if (ipa3_add_hdr_proc_ctx( - (struct ipa_ioc_add_hdr_proc_ctx *)param)) { + (struct ipa_ioc_add_hdr_proc_ctx *)param, true)) { retval = -EFAULT; break; } @@ -1812,7 +1853,22 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } break; - default: /* redundant, as cmd was checked against MAXNR */ + case IPA_IOC_CLEANUP: + /*Route and filter rules will also be clean*/ + IPADBG("Got IPA_IOC_CLEANUP\n"); + retval = ipa3_reset_hdr(true); + memset(&nat_del, 0, sizeof(nat_del)); + nat_del.table_index = 0; + retval = ipa3_nat_del_cmd(&nat_del); + retval = ipa3_clean_modem_rule(); + break; + + case IPA_IOC_QUERY_WLAN_CLIENT: + IPADBG("Got IPA_IOC_QUERY_WLAN_CLIENT\n"); + retval = ipa3_resend_wlan_msg(); + break; + + default: IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); return -ENOTTY; } @@ -1823,13 +1879,13 @@ static long ipa3_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) } /** -* ipa3_setup_dflt_rt_tables() - Setup default routing tables -* -* Return codes: -* 0: success -* -ENOMEM: failed to allocate memory -* -EPERM: failed to add the tables -*/ + * ipa3_setup_dflt_rt_tables() - Setup default routing tables + * + * Return codes: + * 0: success + * -ENOMEM: failed to allocate memory + * -EPERM: failed to add the tables + */ int ipa3_setup_dflt_rt_tables(void) { struct ipa_ioc_add_rt_rule *rt_rule; @@ -2010,14 +2066,14 @@ static int ipa3_init_smem_region(int memory_region_size, } /** -* ipa3_init_q6_smem() - Initialize Q6 general memory and -* header memory regions in IPA. -* -* Return codes: -* 0: success -* -ENOMEM: failed to allocate dma memory -* -EFAULT: failed to send IPA command to initialize the memory -*/ + * ipa3_init_q6_smem() - Initialize Q6 general memory and + * header memory regions in IPA. + * + * Return codes: + * 0: success + * -ENOMEM: failed to allocate dma memory + * -EFAULT: failed to send IPA command to initialize the memory + */ int ipa3_init_q6_smem(void) { int rc; @@ -2546,12 +2602,12 @@ static int ipa3_q6_set_ex_path_to_apps(void) } /** -* ipa3_q6_pre_shutdown_cleanup() - A cleanup for all Q6 related configuration -* in IPA HW. This is performed in case of SSR. -* -* This is a mandatory procedure, in case one of the steps fails, the -* AP needs to restart. -*/ + * ipa3_q6_pre_shutdown_cleanup() - A cleanup for all Q6 related configuration + * in IPA HW. This is performed in case of SSR. + * + * This is a mandatory procedure, in case one of the steps fails, the + * AP needs to restart. + */ void ipa3_q6_pre_shutdown_cleanup(void) { IPADBG_LOW("ENTER\n"); @@ -2569,8 +2625,8 @@ void ipa3_q6_pre_shutdown_cleanup(void) BUG(); } /* Remove delay from Q6 PRODs to avoid pending descriptors - * on pipe reset procedure - */ + * on pipe reset procedure + */ ipa3_q6_pipe_delay(false); IPA_ACTIVE_CLIENTS_DEC_SIMPLE(); @@ -3465,11 +3521,11 @@ static unsigned int ipa3_get_bus_vote(void) } /** -* ipa3_enable_clks() - Turn on IPA clocks -* -* Return codes: -* None -*/ + * ipa3_enable_clks() - Turn on IPA clocks + * + * Return codes: + * None + */ void ipa3_enable_clks(void) { IPADBG("enabling IPA clocks and bus voting\n"); @@ -3498,11 +3554,11 @@ void _ipa_disable_clks_v3_0(void) } /** -* ipa3_disable_clks() - Turn off IPA clocks -* -* Return codes: -* None -*/ + * ipa3_disable_clks() - Turn off IPA clocks + * + * Return codes: + * None + */ void ipa3_disable_clks(void) { IPADBG("disabling IPA clocks and bus voting\n"); @@ -3541,28 +3597,28 @@ static void ipa3_start_tag_process(struct work_struct *work) } /** -* ipa3_active_clients_log_mod() - Log a modification in the active clients -* reference count -* -* This method logs any modification in the active clients reference count: -* It logs the modification in the circular history buffer -* It logs the modification in the hash table - looking for an entry, -* creating one if needed and deleting one if needed. -* -* @id: ipa3_active client logging info struct to hold the log information -* @inc: a boolean variable to indicate whether the modification is an increase -* or decrease -* @int_ctx: a boolean variable to indicate whether this call is being made from -* an interrupt context and therefore should allocate GFP_ATOMIC memory -* -* Method process: -* - Hash the unique identifier string -* - Find the hash in the table -* 1)If found, increase or decrease the reference count -* 2)If not found, allocate a new hash table entry struct and initialize it -* - Remove and deallocate unneeded data structure -* - Log the call in the circular history buffer (unless it is a simple call) -*/ + * ipa3_active_clients_log_mod() - Log a modification in the active clients + * reference count + * + * This method logs any modification in the active clients reference count: + * It logs the modification in the circular history buffer + * It logs the modification in the hash table - looking for an entry, + * creating one if needed and deleting one if needed. + * + * @id: ipa3_active client logging info struct to hold the log information + * @inc: a boolean variable to indicate whether the modification is an increase + * or decrease + * @int_ctx: a boolean variable to indicate whether this call is being made from + * an interrupt context and therefore should allocate GFP_ATOMIC memory + * + * Method process: + * - Hash the unique identifier string + * - Find the hash in the table + * 1)If found, increase or decrease the reference count + * 2)If not found, allocate a new hash table entry struct and initialize it + * - Remove and deallocate unneeded data structure + * - Log the call in the circular history buffer (unless it is a simple call) + */ void ipa3_active_clients_log_mod(struct ipa_active_client_logging_info *id, bool inc, bool int_ctx) { @@ -3632,12 +3688,12 @@ void ipa3_active_clients_log_inc(struct ipa_active_client_logging_info *id, } /** -* ipa3_inc_client_enable_clks() - Increase active clients counter, and -* enable ipa clocks if necessary -* -* Return codes: -* None -*/ + * ipa3_inc_client_enable_clks() - Increase active clients counter, and + * enable ipa clocks if necessary + * + * Return codes: + * None + */ void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id) { ipa3_active_clients_lock(); @@ -3650,13 +3706,13 @@ void ipa3_inc_client_enable_clks(struct ipa_active_client_logging_info *id) } /** -* ipa3_inc_client_enable_clks_no_block() - Only increment the number of active -* clients if no asynchronous actions should be done. Asynchronous actions are -* locking a mutex and waking up IPA HW. -* -* Return codes: 0 for success -* -EPERM if an asynchronous action should have been done -*/ + * ipa3_inc_client_enable_clks_no_block() - Only increment the number of active + * clients if no asynchronous actions should be done. Asynchronous actions are + * locking a mutex and waking up IPA HW. + * + * Return codes: 0 for success + * -EPERM if an asynchronous action should have been done + */ int ipa3_inc_client_enable_clks_no_block(struct ipa_active_client_logging_info *id) { @@ -3718,12 +3774,12 @@ void ipa3_dec_client_disable_clks(struct ipa_active_client_logging_info *id) } /** -* ipa3_inc_acquire_wakelock() - Increase active clients counter, and -* acquire wakelock if necessary -* -* Return codes: -* None -*/ + * ipa3_inc_acquire_wakelock() - Increase active clients counter, and + * acquire wakelock if necessary + * + * Return codes: + * None + */ void ipa3_inc_acquire_wakelock(void) { unsigned long flags; @@ -3835,12 +3891,12 @@ static void ipa3_sps_process_irq_schedule_rel(void) } /** -* ipa3_suspend_handler() - Handles the suspend interrupt: -* wakes up the suspended peripheral by requesting its consumer -* @interrupt: Interrupt type -* @private_data: The client's private data -* @interrupt_data: Interrupt specific information data -*/ + * ipa3_suspend_handler() - Handles the suspend interrupt: + * wakes up the suspended peripheral by requesting its consumer + * @interrupt: Interrupt type + * @private_data: The client's private data + * @interrupt_data: Interrupt specific information data + */ void ipa3_suspend_handler(enum ipa_irq_type interrupt, void *private_data, void *interrupt_data) @@ -3903,12 +3959,12 @@ void ipa3_suspend_handler(enum ipa_irq_type interrupt, } /** -* ipa3_restore_suspend_handler() - restores the original suspend IRQ handler -* as it was registered in the IPA init sequence. -* Return codes: -* 0: success -* -EPERM: failed to remove current handler or failed to add original handler -* */ + * ipa3_restore_suspend_handler() - restores the original suspend IRQ handler + * as it was registered in the IPA init sequence. + * Return codes: + * 0: success + * -EPERM: failed to remove current handler or failed to add original handler + */ int ipa3_restore_suspend_handler(void) { int result = 0; @@ -4497,39 +4553,37 @@ static int ipa3_tz_unlock_reg(struct ipa3_context *ipa3_ctx) } /** -* ipa3_pre_init() - Initialize the IPA Driver. -* This part contains all initialization which doesn't require IPA HW, such -* as structure allocations and initializations, register writes, etc. -* -* @resource_p: contain platform specific values from DST file -* @pdev: The platform device structure representing the IPA driver -* -* Function initialization process: -* - Allocate memory for the driver context data struct -* - Initializing the ipa3_ctx with: -* 1)parsed values from the dts file -* 2)parameters passed to the module initialization -* 3)read HW values(such as core memory size) -* - Map IPA core registers to CPU memory -* - Restart IPA core(HW reset) -* - Set configuration for IPA BAM via BAM_CNFG_BITS -* - Initialize the look-aside caches(kmem_cache/slab) for filter, -* routing and IPA-tree -* - Create memory pool with 4 objects for DMA operations(each object -* is 512Bytes long), this object will be use for tx(A5->IPA) -* - Initialize lists head(routing,filter,hdr,system pipes) -* - Initialize mutexes (for ipa_ctx and NAT memory mutexes) -* - Initialize spinlocks (for list related to A5<->IPA pipes) -* - Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq" -* - Initialize Red-Black-Tree(s) for handles of header,routing rule, -* routing table ,filtering rule -* - Initialize the filter block by committing IPV4 and IPV6 default rules -* - Create empty routing table in system memory(no committing) -* - Initialize pipes memory pool with ipa3_pipe_mem_init for supported platforms -* - Create a char-device for IPA -* - Initialize IPA RM (resource manager) -* - Configure GSI registers (in GSI case) -*/ + * ipa3_pre_init() - Initialize the IPA Driver. + * This part contains all initialization which doesn't require IPA HW, such + * as structure allocations and initializations, register writes, etc. + * + * @resource_p: contain platform specific values from DST file + * @pdev: The platform device structure representing the IPA driver + * + * Function initialization process: + * Allocate memory for the driver context data struct + * Initializing the ipa3_ctx with : + * 1)parsed values from the dts file + * 2)parameters passed to the module initialization + * 3)read HW values(such as core memory size) + * Map IPA core registers to CPU memory + * Restart IPA core(HW reset) + * Initialize the look-aside caches(kmem_cache/slab) for filter, + * routing and IPA-tree + * Create memory pool with 4 objects for DMA operations(each object + * is 512Bytes long), this object will be use for tx(A5->IPA) + * Initialize lists head(routing, hdr, system pipes) + * Initialize mutexes (for ipa_ctx and NAT memory mutexes) + * Initialize spinlocks (for list related to A5<->IPA pipes) + * Initialize 2 single-threaded work-queue named "ipa rx wq" and "ipa tx wq" + * Initialize Red-Black-Tree(s) for handles of header,routing rule, + * routing table ,filtering rule + * Initialize the filter block by committing IPV4 and IPV6 default rules + * Create empty routing table in system memory(no committing) + * Create a char-device for IPA + * Initialize IPA RM (resource manager) + * Configure GSI registers (in GSI case) + */ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, struct device *ipa_dev) { @@ -4887,6 +4941,10 @@ static int ipa3_pre_init(const struct ipa3_plat_drv_res *resource_p, init_waitqueue_head(&ipa3_ctx->msg_waitq); mutex_init(&ipa3_ctx->msg_lock); + /* store wlan client-connect-msg-list */ + INIT_LIST_HEAD(&ipa3_ctx->msg_wlan_client_list); + mutex_init(&ipa3_ctx->msg_wlan_client_lock); + mutex_init(&ipa3_ctx->lock); mutex_init(&ipa3_ctx->nat_mem.lock); mutex_init(&ipa3_ctx->q6_proxy_clk_vote_mutex); @@ -5873,7 +5931,7 @@ int ipa3_plat_drv_probe(struct platform_device *pdev_p, * * Returns -EAGAIN to runtime_pm framework in case IPA is in use by AP. * This will postpone the suspend operation until IPA is no longer used by AP. -*/ + */ int ipa3_ap_suspend(struct device *dev) { int i; @@ -5899,14 +5957,14 @@ int ipa3_ap_suspend(struct device *dev) } /** -* ipa3_ap_resume() - resume callback for runtime_pm -* @dev: pointer to device -* -* This callback will be invoked by the runtime_pm framework when an AP resume -* operation is invoked. -* -* Always returns 0 since resume should always succeed. -*/ + * ipa3_ap_resume() - resume callback for runtime_pm + * @dev: pointer to device + * + * This callback will be invoked by the runtime_pm framework when an AP resume + * operation is invoked. + * + * Always returns 0 since resume should always succeed. + */ int ipa3_ap_resume(struct device *dev) { return 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c index 128b859ee152..03c846ea9596 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_flt.c @@ -784,7 +784,7 @@ error: static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry, const struct ipa_flt_rule *rule, struct ipa3_rt_tbl *rt_tbl, - struct ipa3_flt_tbl *tbl) + struct ipa3_flt_tbl *tbl, bool user) { int id; @@ -809,6 +809,7 @@ static int __ipa_create_flt_entry(struct ipa3_flt_entry **entry, } } (*entry)->rule_id = id; + (*entry)->ipacm_installed = user; return 0; @@ -846,7 +847,7 @@ ipa_insert_failed: static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, const struct ipa_flt_rule *rule, u8 add_rear, - u32 *rule_hdl) + u32 *rule_hdl, bool user) { struct ipa3_flt_entry *entry; struct ipa3_rt_tbl *rt_tbl = NULL; @@ -854,7 +855,7 @@ static int __ipa_add_flt_rule(struct ipa3_flt_tbl *tbl, enum ipa_ip_type ip, if (__ipa_validate_flt_rule(rule, &rt_tbl, ip)) goto error; - if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl)) + if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl, user)) goto error; if (add_rear) { @@ -904,7 +905,7 @@ static int __ipa_add_flt_rule_after(struct ipa3_flt_tbl *tbl, if (__ipa_validate_flt_rule(rule, &rt_tbl, ip)) goto error; - if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl)) + if (__ipa_create_flt_entry(&entry, rule, rt_tbl, tbl, true)) goto error; list_add(&entry->link, &((*add_after_entry)->link)); @@ -1054,7 +1055,7 @@ static int __ipa_add_flt_get_ep_idx(enum ipa_client_type ep, int *ipa_ep_idx) static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, const struct ipa_flt_rule *rule, u8 add_rear, - u32 *rule_hdl) + u32 *rule_hdl, bool user) { struct ipa3_flt_tbl *tbl; int ipa_ep_idx; @@ -1072,12 +1073,13 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][ip]; IPADBG_LOW("add ep flt rule ip=%d ep=%d\n", ip, ep); - return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl); + return __ipa_add_flt_rule(tbl, ip, rule, add_rear, rule_hdl, user); } /** * ipa3_add_flt_rule() - Add the specified filtering rules to SW and optionally * commit to IPA HW + * @rules: [inout] set of filtering rules to add * * Returns: 0 on success, negative on failure * @@ -1085,6 +1087,20 @@ static int __ipa_add_ep_flt_rule(enum ipa_ip_type ip, enum ipa_client_type ep, */ int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) { + return ipa3_add_flt_rule_usr(rules, false); +} +/** + * ipa3_add_flt_rule_usr() - Add the specified filtering rules to + * SW and optionally commit to IPA HW + * @rules: [inout] set of filtering rules to add + * @user_only: [in] indicate rules installed by userspace + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa3_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, bool user_only) +{ int i; int result; @@ -1100,7 +1116,8 @@ int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) result = __ipa_add_ep_flt_rule(rules->ip, rules->ep, &rules->rules[i].rule, rules->rules[i].at_rear, - &rules->rules[i].flt_rule_hdl); + &rules->rules[i].flt_rule_hdl, + user_only); else result = -1; @@ -1347,18 +1364,20 @@ bail: * ipa3_reset_flt() - Reset the current SW filtering table of specified type * (does not commit to HW) * @ip: [in] the family of routing tables + * @user_only: [in] indicate rules deleted by userspace * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa3_reset_flt(enum ipa_ip_type ip) +int ipa3_reset_flt(enum ipa_ip_type ip, bool user_only) { struct ipa3_flt_tbl *tbl; struct ipa3_flt_entry *entry; struct ipa3_flt_entry *next; int i; int id; + int rule_id; if (ip >= IPA_IP_MAX) { IPAERR_RL("bad parm\n"); @@ -1378,21 +1397,27 @@ int ipa3_reset_flt(enum ipa_ip_type ip) mutex_unlock(&ipa3_ctx->lock); return -EFAULT; } - list_del(&entry->link); - entry->tbl->rule_cnt--; - if (entry->rt_tbl) - entry->rt_tbl->ref_cnt--; - /* if rule id was allocated from idr, remove it */ - if ((entry->rule_id < ipahal_get_rule_id_hi_bit()) && - (entry->rule_id >= ipahal_get_low_rule_id())) - idr_remove(&entry->tbl->rule_ids, - entry->rule_id); - entry->cookie = 0; - id = entry->id; - kmem_cache_free(ipa3_ctx->flt_rule_cache, entry); - - /* remove the handle from the database */ - ipa3_id_remove(id); + + if (!user_only || + entry->ipacm_installed) { + list_del(&entry->link); + entry->tbl->rule_cnt--; + if (entry->rt_tbl) + entry->rt_tbl->ref_cnt--; + /* if rule id was allocated from idr, remove */ + rule_id = entry->rule_id; + id = entry->id; + if ((rule_id < ipahal_get_rule_id_hi_bit()) && + (rule_id >= ipahal_get_low_rule_id())) + idr_remove(&entry->tbl->rule_ids, + rule_id); + entry->cookie = 0; + kmem_cache_free(ipa3_ctx->flt_rule_cache, + entry); + + /* remove the handle from the database */ + ipa3_id_remove(id); + } } } mutex_unlock(&ipa3_ctx->lock); @@ -1418,14 +1443,14 @@ void ipa3_install_dflt_flt_rules(u32 ipa_ep_idx) tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v4]; rule.action = IPA_PASS_TO_EXCEPTION; __ipa_add_flt_rule(tbl, IPA_IP_v4, &rule, true, - &ep->dflt_flt4_rule_hdl); + &ep->dflt_flt4_rule_hdl, false); ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v4); tbl->sticky_rear = true; tbl = &ipa3_ctx->flt_tbl[ipa_ep_idx][IPA_IP_v6]; rule.action = IPA_PASS_TO_EXCEPTION; __ipa_add_flt_rule(tbl, IPA_IP_v6, &rule, true, - &ep->dflt_flt6_rule_hdl); + &ep->dflt_flt6_rule_hdl, false); ipa3_ctx->ctrl->ipa3_commit_flt(IPA_IP_v6); tbl->sticky_rear = true; mutex_unlock(&ipa3_ctx->lock); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c index b5b8643f24a9..f71eb952cde2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_hdr.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -315,7 +315,7 @@ end: } static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, - bool add_ref_hdr) + bool add_ref_hdr, bool user_only) { struct ipa3_hdr_entry *hdr_entry; struct ipa3_hdr_proc_ctx_entry *entry; @@ -360,6 +360,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, if (add_ref_hdr) hdr_entry->ref_cnt++; entry->cookie = IPA_PROC_HDR_COOKIE; + entry->ipacm_installed = user_only; needed_len = ipahal_get_proc_ctx_needed_len(proc_ctx->type); @@ -396,6 +397,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, */ offset->offset = htbl->end; offset->bin = bin; + offset->ipacm_installed = user_only; htbl->end += ipa_hdr_proc_ctx_bin_sz[bin]; list_add(&offset->link, &htbl->head_offset_list[bin]); @@ -404,6 +406,7 @@ static int __ipa_add_hdr_proc_ctx(struct ipa_hdr_proc_ctx_add *proc_ctx, offset = list_first_entry(&htbl->head_free_offset_list[bin], struct ipa3_hdr_proc_ctx_offset_entry, link); + offset->ipacm_installed = user_only; list_move(&offset->link, &htbl->head_offset_list[bin]); } @@ -441,7 +444,7 @@ bad_len: } -static int __ipa_add_hdr(struct ipa_hdr_add *hdr) +static int __ipa_add_hdr(struct ipa_hdr_add *hdr, bool user) { struct ipa3_hdr_entry *entry; struct ipa_hdr_offset_entry *offset = NULL; @@ -476,6 +479,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) entry->is_eth2_ofst_valid = hdr->is_eth2_ofst_valid; entry->eth2_ofst = hdr->eth2_ofst; entry->cookie = IPA_HDR_COOKIE; + entry->ipacm_installed = user; if (hdr->hdr_len <= ipa_hdr_bin_sz[IPA_HDR_BIN0]) bin = IPA_HDR_BIN0; @@ -527,6 +531,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) list_add(&offset->link, &htbl->head_offset_list[bin]); entry->offset_entry = offset; + offset->ipacm_installed = user; } } else { entry->is_hdr_proc_ctx = false; @@ -535,6 +540,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) struct ipa_hdr_offset_entry, link); list_move(&offset->link, &htbl->head_offset_list[bin]); entry->offset_entry = offset; + offset->ipacm_installed = user; } list_add(&entry->link, &htbl->head_hdr_entry_list); @@ -566,7 +572,7 @@ static int __ipa_add_hdr(struct ipa_hdr_add *hdr) IPADBG("adding processing context for header %s\n", hdr->name); proc_ctx.type = IPA_HDR_PROC_NONE; proc_ctx.hdr_hdl = id; - if (__ipa_add_hdr_proc_ctx(&proc_ctx, false)) { + if (__ipa_add_hdr_proc_ctx(&proc_ctx, false, user)) { IPAERR("failed to add hdr proc ctx\n"); goto fail_add_proc_ctx; } @@ -728,6 +734,21 @@ int __ipa3_del_hdr(u32 hdr_hdl, bool by_user) */ int ipa3_add_hdr(struct ipa_ioc_add_hdr *hdrs) { + return ipa3_add_hdr_usr(hdrs, false); +} + +/** + * ipa3_add_hdr_usr() - add the specified headers to SW + * and optionally commit them to IPA HW + * @hdrs: [inout] set of headers to add + * @user_only: [in] indicate installed from user + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa3_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool user_only) +{ int i; int result = -EFAULT; @@ -740,7 +761,7 @@ int ipa3_add_hdr(struct ipa_ioc_add_hdr *hdrs) IPADBG("adding %d headers to IPA driver internal data struct\n", hdrs->num_hdrs); for (i = 0; i < hdrs->num_hdrs; i++) { - if (__ipa_add_hdr(&hdrs->hdr[i])) { + if (__ipa_add_hdr(&hdrs->hdr[i], user_only)) { IPAERR_RL("failed to add hdr %d\n", i); hdrs->hdr[i].status = -1; } else { @@ -821,12 +842,14 @@ int ipa3_del_hdr(struct ipa_ioc_del_hdr *hdls) * ipa3_add_hdr_proc_ctx() - add the specified headers to SW * and optionally commit them to IPA HW * @proc_ctxs: [inout] set of processing context headers to add + * @user_only: [in] indicate installed by user-space module * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) +int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs, + bool user_only) { int i; int result = -EFAULT; @@ -840,7 +863,8 @@ int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) IPADBG("adding %d header processing contextes to IPA driver\n", proc_ctxs->num_proc_ctxs); for (i = 0; i < proc_ctxs->num_proc_ctxs; i++) { - if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], true)) { + if (__ipa_add_hdr_proc_ctx(&proc_ctxs->proc_ctx[i], + true, user_only)) { IPAERR_RL("failed to add hdr pric ctx %d\n", i); proc_ctxs->proc_ctx[i].status = -1; } else { @@ -955,11 +979,12 @@ bail: * ipa3_reset_hdr() - reset the current header table in SW (does not commit to * HW) * + * @user_only: [in] indicate delete rules installed by userspace * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa3_reset_hdr(void) +int ipa3_reset_hdr(bool user_only) { struct ipa3_hdr_entry *entry; struct ipa3_hdr_entry *next; @@ -975,9 +1000,9 @@ int ipa3_reset_hdr(void) * issue a reset on the routing module since routing rules point to * header table entries */ - if (ipa3_reset_rt(IPA_IP_v4)) + if (ipa3_reset_rt(IPA_IP_v4, user_only)) IPAERR("fail to reset v4 rt\n"); - if (ipa3_reset_rt(IPA_IP_v6)) + if (ipa3_reset_rt(IPA_IP_v6, user_only)) IPAERR("fail to reset v4 rt\n"); mutex_lock(&ipa3_ctx->lock); @@ -1006,21 +1031,23 @@ int ipa3_reset_hdr(void) WARN_ON(1); return -EFAULT; } - if (entry->is_hdr_proc_ctx) { - dma_unmap_single(ipa3_ctx->pdev, - entry->phys_base, - entry->hdr_len, - DMA_TO_DEVICE); - entry->proc_ctx = NULL; - } - list_del(&entry->link); - entry->ref_cnt = 0; - entry->cookie = 0; - /* remove the handle from the database */ - ipa3_id_remove(entry->id); - kmem_cache_free(ipa3_ctx->hdr_cache, entry); + if (!user_only || entry->ipacm_installed) { + if (entry->is_hdr_proc_ctx) { + dma_unmap_single(ipa3_ctx->pdev, + entry->phys_base, + entry->hdr_len, + DMA_TO_DEVICE); + entry->proc_ctx = NULL; + } + list_del(&entry->link); + entry->ref_cnt = 0; + entry->cookie = 0; + /* remove the handle from the database */ + ipa3_id_remove(entry->id); + kmem_cache_free(ipa3_ctx->hdr_cache, entry); + } } for (i = 0; i < IPA_HDR_BIN_MAX; i++) { list_for_each_entry_safe(off_entry, off_next, @@ -1034,14 +1061,23 @@ int ipa3_reset_hdr(void) if (off_entry->offset == 0) continue; - list_del(&off_entry->link); - kmem_cache_free(ipa3_ctx->hdr_offset_cache, off_entry); + if (!user_only || + off_entry->ipacm_installed) { + list_del(&off_entry->link); + kmem_cache_free(ipa3_ctx->hdr_offset_cache, + off_entry); + } } list_for_each_entry_safe(off_entry, off_next, &ipa3_ctx->hdr_tbl.head_free_offset_list[i], link) { - list_del(&off_entry->link); - kmem_cache_free(ipa3_ctx->hdr_offset_cache, off_entry); + + if (!user_only || + off_entry->ipacm_installed) { + list_del(&off_entry->link); + kmem_cache_free(ipa3_ctx->hdr_offset_cache, + off_entry); + } } } /* there is one header of size 8 */ @@ -1060,30 +1096,43 @@ int ipa3_reset_hdr(void) WARN_ON(1); return -EFAULT; } - list_del(&ctx_entry->link); - ctx_entry->ref_cnt = 0; - ctx_entry->cookie = 0; - /* remove the handle from the database */ - ipa3_id_remove(ctx_entry->id); - kmem_cache_free(ipa3_ctx->hdr_proc_ctx_cache, ctx_entry); + if (!user_only || + ctx_entry->ipacm_installed) { + list_del(&ctx_entry->link); + ctx_entry->ref_cnt = 0; + ctx_entry->cookie = 0; + /* remove the handle from the database */ + ipa3_id_remove(ctx_entry->id); + kmem_cache_free(ipa3_ctx->hdr_proc_ctx_cache, + ctx_entry); + } } for (i = 0; i < IPA_HDR_PROC_CTX_BIN_MAX; i++) { list_for_each_entry_safe(ctx_off_entry, ctx_off_next, &ipa3_ctx->hdr_proc_ctx_tbl.head_offset_list[i], link) { - list_del(&ctx_off_entry->link); - kmem_cache_free(ipa3_ctx->hdr_proc_ctx_offset_cache, + if (!user_only || + ctx_off_entry->ipacm_installed) { + list_del(&ctx_off_entry->link); + kmem_cache_free( + ipa3_ctx->hdr_proc_ctx_offset_cache, ctx_off_entry); + } } list_for_each_entry_safe(ctx_off_entry, ctx_off_next, &ipa3_ctx->hdr_proc_ctx_tbl.head_free_offset_list[i], link) { - list_del(&ctx_off_entry->link); - kmem_cache_free(ipa3_ctx->hdr_proc_ctx_offset_cache, - ctx_off_entry); + + if (!user_only || + ctx_off_entry->ipacm_installed) { + list_del(&ctx_off_entry->link); + kmem_cache_free( + ipa3_ctx->hdr_proc_ctx_offset_cache, + ctx_off_entry); + } } } ipa3_ctx->hdr_proc_ctx_tbl.end = 0; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index 7bf56688a9e7..ea98433bbdf2 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -233,6 +233,7 @@ struct ipa_smmu_cb_ctx { * @prio: rule 10bit priority which defines the order of the rule * among other rules at the same integrated table * @rule_id: rule 10bit ID to be returned in packet status + * @ipacm_installed: indicate if installed by ipacm */ struct ipa3_flt_entry { struct list_head link; @@ -244,6 +245,7 @@ struct ipa3_flt_entry { int id; u16 prio; u16 rule_id; + bool ipacm_installed; }; /** @@ -300,6 +302,7 @@ struct ipa3_rt_tbl { * @is_eth2_ofst_valid: is eth2_ofst field valid? * @eth2_ofst: offset to start of Ethernet-II/802.3 header * @user_deleted: is the header deleted by the user? + * @ipacm_installed: indicate if installed by ipacm */ struct ipa3_hdr_entry { struct list_head link; @@ -318,6 +321,7 @@ struct ipa3_hdr_entry { u8 is_eth2_ofst_valid; u16 eth2_ofst; bool user_deleted; + bool ipacm_installed; }; /** @@ -341,11 +345,13 @@ struct ipa3_hdr_tbl { * @link: entry's link in global processing context header offset entries list * @offset: the offset * @bin: bin + * @ipacm_installed: indicate if installed by ipacm */ struct ipa3_hdr_proc_ctx_offset_entry { struct list_head link; u32 offset; u32 bin; + bool ipacm_installed; }; /** @@ -358,6 +364,7 @@ struct ipa3_hdr_proc_ctx_offset_entry { * @ref_cnt: reference counter of routing table * @id: processing context header entry id * @user_deleted: is the hdr processing context deleted by the user? + * @ipacm_installed: indicate if installed by ipacm */ struct ipa3_hdr_proc_ctx_entry { struct list_head link; @@ -368,6 +375,7 @@ struct ipa3_hdr_proc_ctx_entry { u32 ref_cnt; int id; bool user_deleted; + bool ipacm_installed; }; /** @@ -423,6 +431,8 @@ struct ipa3_flt_tbl { * @prio: rule 10bit priority which defines the order of the rule * among other rules at the integrated same table * @rule_id: rule 10bit ID to be returned in packet status + * @rule_id_valid: indicate if rule_id_valid valid or not? + * @ipacm_installed: indicate if installed by ipacm */ struct ipa3_rt_entry { struct list_head link; @@ -436,6 +446,7 @@ struct ipa3_rt_entry { u16 prio; u16 rule_id; u16 rule_id_valid; + bool ipacm_installed; }; /** @@ -1217,6 +1228,8 @@ struct ipa3_context { struct list_head msg_list; struct list_head pull_msg_list; struct mutex msg_lock; + struct list_head msg_wlan_client_list; + struct mutex msg_wlan_client_lock; wait_queue_head_t msg_waitq; enum ipa_hw_type ipa_hw_type; enum ipa3_hw_mode ipa3_hw_mode; @@ -1591,13 +1604,15 @@ int ipa3_cfg_ep_ctrl(u32 clnt_hdl, const struct ipa_ep_cfg_ctrl *ep_ctrl); */ int ipa3_add_hdr(struct ipa_ioc_add_hdr *hdrs); +int ipa3_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool by_user); + int ipa3_del_hdr(struct ipa_ioc_del_hdr *hdls); int ipa3_del_hdr_by_user(struct ipa_ioc_del_hdr *hdls, bool by_user); int ipa3_commit_hdr(void); -int ipa3_reset_hdr(void); +int ipa3_reset_hdr(bool user_only); int ipa3_get_hdr(struct ipa_ioc_get_hdr *lookup); @@ -1608,7 +1623,8 @@ int ipa3_copy_hdr(struct ipa_ioc_copy_hdr *copy); /* * Header Processing Context */ -int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs); +int ipa3_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs, + bool user_only); int ipa3_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls); @@ -1620,6 +1636,9 @@ int ipa3_del_hdr_proc_ctx_by_user(struct ipa_ioc_del_hdr_proc_ctx *hdls, */ int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules); +int ipa3_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, + bool user_only); + int ipa3_add_rt_rule_ext(struct ipa_ioc_add_rt_rule_ext *rules); int ipa3_add_rt_rule_after(struct ipa_ioc_add_rt_rule_after *rules); @@ -1628,7 +1647,7 @@ int ipa3_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls); int ipa3_commit_rt(enum ipa_ip_type ip); -int ipa3_reset_rt(enum ipa_ip_type ip); +int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only); int ipa3_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup); @@ -1643,6 +1662,9 @@ int ipa3_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *rules); */ int ipa3_add_flt_rule(struct ipa_ioc_add_flt_rule *rules); +int ipa3_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, + bool user_only); + int ipa3_add_flt_rule_after(struct ipa_ioc_add_flt_rule_after *rules); int ipa3_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls); @@ -1651,7 +1673,7 @@ int ipa3_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *rules); int ipa3_commit_flt(enum ipa_ip_type ip); -int ipa3_reset_flt(enum ipa_ip_type ip); +int ipa3_reset_flt(enum ipa_ip_type ip, bool user_only); /* * NAT @@ -1672,6 +1694,7 @@ int ipa3_del_nat_table(struct ipa_ioc_nat_ipv6ct_table_del *del); */ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff, ipa_msg_free_fn callback); +int ipa3_resend_wlan_msg(void); int ipa3_register_pull_msg(struct ipa_msg_meta *meta, ipa_msg_pull_fn callback); int ipa3_deregister_pull_msg(struct ipa_msg_meta *meta); @@ -1704,7 +1727,7 @@ int ipa3_tx_dp(enum ipa_client_type dst, struct sk_buff *skb, * To transfer multiple data packets * While passing the data descriptor list, the anchor node * should be of type struct ipa_tx_data_desc not list_head -*/ + */ int ipa3_tx_dp_mul(enum ipa_client_type dst, struct ipa_tx_data_desc *data_desc); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c index 76f37162f495..2039c1ba0a3c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_intf.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,6 +13,7 @@ #include #include #include "ipa_i.h" +#include struct ipa3_intf { char name[IPA_RESOURCE_NAME_MAX]; @@ -387,6 +388,108 @@ static void ipa3_send_msg_free(void *buff, u32 len, u32 type) kfree(buff); } +static int wlan_msg_process(struct ipa_msg_meta *meta, void *buff) +{ + struct ipa3_push_msg *msg_dup; + struct ipa_wlan_msg_ex *event_ex_cur_con = NULL; + struct ipa_wlan_msg_ex *event_ex_list = NULL; + struct ipa_wlan_msg *event_ex_cur_discon = NULL; + void *data_dup = NULL; + struct ipa3_push_msg *entry; + struct ipa3_push_msg *next; + int cnt = 0, total = 0, max = 0; + uint8_t mac[IPA_MAC_ADDR_SIZE]; + uint8_t mac2[IPA_MAC_ADDR_SIZE]; + + if (meta->msg_type == WLAN_CLIENT_CONNECT_EX) { + /* debug print */ + event_ex_cur_con = buff; + for (cnt = 0; cnt < event_ex_cur_con->num_of_attribs; cnt++) { + if (event_ex_cur_con->attribs[cnt].attrib_type == + WLAN_HDR_ATTRIB_MAC_ADDR) { + IPADBG("%02x:%02x:%02x:%02x:%02x:%02x,(%d)\n", + event_ex_cur_con->attribs[cnt].u.mac_addr[0], + event_ex_cur_con->attribs[cnt].u.mac_addr[1], + event_ex_cur_con->attribs[cnt].u.mac_addr[2], + event_ex_cur_con->attribs[cnt].u.mac_addr[3], + event_ex_cur_con->attribs[cnt].u.mac_addr[4], + event_ex_cur_con->attribs[cnt].u.mac_addr[5], + meta->msg_type); + } + } + + mutex_lock(&ipa3_ctx->msg_wlan_client_lock); + msg_dup = kzalloc(sizeof(struct ipa3_push_msg), GFP_KERNEL); + if (msg_dup == NULL) { + IPAERR("fail to alloc ipa_msg container\n"); + return -ENOMEM; + } + msg_dup->meta = *meta; + if (meta->msg_len > 0 && buff) { + data_dup = kmalloc(meta->msg_len, GFP_KERNEL); + if (data_dup == NULL) { + IPAERR("fail to alloc data_dup container\n"); + kfree(msg_dup); + return -ENOMEM; + } + memcpy(data_dup, buff, meta->msg_len); + msg_dup->buff = data_dup; + msg_dup->callback = ipa3_send_msg_free; + } + list_add_tail(&msg_dup->link, &ipa3_ctx->msg_wlan_client_list); + mutex_unlock(&ipa3_ctx->msg_wlan_client_lock); + } + + /* remove the cache */ + if (meta->msg_type == WLAN_CLIENT_DISCONNECT) { + /* debug print */ + event_ex_cur_discon = buff; + IPADBG("Mac %02x:%02x:%02x:%02x:%02x:%02x,msg %d\n", + event_ex_cur_discon->mac_addr[0], + event_ex_cur_discon->mac_addr[1], + event_ex_cur_discon->mac_addr[2], + event_ex_cur_discon->mac_addr[3], + event_ex_cur_discon->mac_addr[4], + event_ex_cur_discon->mac_addr[5], + meta->msg_type); + memcpy(mac2, + event_ex_cur_discon->mac_addr, + sizeof(mac2)); + + mutex_lock(&ipa3_ctx->msg_wlan_client_lock); + list_for_each_entry_safe(entry, next, + &ipa3_ctx->msg_wlan_client_list, + link) { + event_ex_list = entry->buff; + max = event_ex_list->num_of_attribs; + for (cnt = 0; cnt < max; cnt++) { + memcpy(mac, + event_ex_list->attribs[cnt].u.mac_addr, + sizeof(mac)); + if (event_ex_list->attribs[cnt].attrib_type == + WLAN_HDR_ATTRIB_MAC_ADDR) { + pr_debug("%02x:%02x:%02x:%02x:%02x:%02x\n", + mac[0], mac[1], mac[2], + mac[3], mac[4], mac[5]); + + /* compare to delete one*/ + if (memcmp(mac2, + mac, + sizeof(mac)) == 0) { + IPADBG("clean %d\n", total); + list_del(&entry->link); + kfree(entry); + break; + } + } + } + total++; + } + mutex_unlock(&ipa3_ctx->msg_wlan_client_lock); + } + return 0; +} + /** * ipa3_send_msg() - Send "message" from kernel client to IPA driver * @meta: [in] message meta-data @@ -409,7 +512,7 @@ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff, void *data = NULL; if (meta == NULL || (buff == NULL && callback != NULL) || - (buff != NULL && callback == NULL)) { + (buff != NULL && callback == NULL) || buff == NULL) { IPAERR_RL("invalid param meta=%p buff=%p, callback=%p\n", meta, buff, callback); return -EINVAL; @@ -441,6 +544,11 @@ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff, mutex_lock(&ipa3_ctx->msg_lock); list_add_tail(&msg->link, &ipa3_ctx->msg_list); + /* support for softap client event cache */ + if (wlan_msg_process(meta, buff)) + IPAERR("wlan_msg_process failed\n"); + + /* unlock only after process */ mutex_unlock(&ipa3_ctx->msg_lock); IPA_STATS_INC_CNT(ipa3_ctx->stats.msg_w[meta->msg_type]); @@ -452,6 +560,73 @@ int ipa3_send_msg(struct ipa_msg_meta *meta, void *buff, } /** + * ipa3_resend_wlan_msg() - Resend cached "message" to IPACM + * + * resend wlan client connect events to user-space + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa3_resend_wlan_msg(void) +{ + struct ipa_wlan_msg_ex *event_ex_list = NULL; + struct ipa3_push_msg *entry; + struct ipa3_push_msg *next; + int cnt = 0, total = 0; + struct ipa3_push_msg *msg; + void *data = NULL; + + IPADBG("\n"); + + mutex_lock(&ipa3_ctx->msg_wlan_client_lock); + list_for_each_entry_safe(entry, next, &ipa3_ctx->msg_wlan_client_list, + link) { + + event_ex_list = entry->buff; + for (cnt = 0; cnt < event_ex_list->num_of_attribs; cnt++) { + if (event_ex_list->attribs[cnt].attrib_type == + WLAN_HDR_ATTRIB_MAC_ADDR) { + IPADBG("%d-Mac %02x:%02x:%02x:%02x:%02x:%02x\n", + total, + event_ex_list->attribs[cnt].u.mac_addr[0], + event_ex_list->attribs[cnt].u.mac_addr[1], + event_ex_list->attribs[cnt].u.mac_addr[2], + event_ex_list->attribs[cnt].u.mac_addr[3], + event_ex_list->attribs[cnt].u.mac_addr[4], + event_ex_list->attribs[cnt].u.mac_addr[5]); + } + } + + msg = kzalloc(sizeof(struct ipa3_push_msg), GFP_KERNEL); + if (msg == NULL) { + IPAERR("fail to alloc ipa_msg container\n"); + mutex_unlock(&ipa3_ctx->msg_wlan_client_lock); + return -ENOMEM; + } + msg->meta = entry->meta; + data = kmalloc(entry->meta.msg_len, GFP_KERNEL); + if (data == NULL) { + IPAERR("fail to alloc data container\n"); + kfree(msg); + mutex_unlock(&ipa3_ctx->msg_wlan_client_lock); + return -ENOMEM; + } + memcpy(data, entry->buff, entry->meta.msg_len); + msg->buff = data; + msg->callback = ipa3_send_msg_free; + mutex_lock(&ipa3_ctx->msg_lock); + list_add_tail(&msg->link, &ipa3_ctx->msg_list); + mutex_unlock(&ipa3_ctx->msg_lock); + wake_up(&ipa3_ctx->msg_waitq); + + total++; + } + mutex_unlock(&ipa3_ctx->msg_wlan_client_lock); + return 0; +} + +/** * ipa3_register_pull_msg() - register pull message type * @meta: [in] message meta-data * @callback: [in] pull callback diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index c0aef7e0ce15..6b90abf787b9 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -605,6 +605,14 @@ int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) int rc; int i; + /* check if modem up */ + if (!ipa3_qmi_indication_fin || + !ipa3_qmi_modem_init_fin || + !ipa_q6_clnt) { + IPAWANDBG("modem QMI haven't up yet\n"); + return -EINVAL; + } + /* check if the filter rules from IPACM is valid */ if (req->filter_spec_list_len == 0) IPAWANDBG("IPACM pass zero rules to Q6\n"); @@ -688,6 +696,14 @@ int ipa3_qmi_filter_request_ex_send( int rc; int i; + /* check if modem up */ + if (!ipa3_qmi_indication_fin || + !ipa3_qmi_modem_init_fin || + !ipa_q6_clnt) { + IPAWANDBG("modem QMI haven't up yet\n"); + return -EINVAL; + } + /* check if the filter rules from IPACM is valid */ if (req->filter_spec_ex_list_len == 0) { IPAWANDBG("IPACM pass zero rules to Q6\n"); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c index fd455f72e09e..0cfe7f92aff7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_rt.c @@ -940,7 +940,7 @@ static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry, const struct ipa_rt_rule *rule, struct ipa3_rt_tbl *tbl, struct ipa3_hdr_entry *hdr, struct ipa3_hdr_proc_ctx_entry *proc_ctx, - u16 rule_id) + u16 rule_id, bool user) { int id; @@ -967,6 +967,7 @@ static int __ipa_create_rt_entry(struct ipa3_rt_entry **entry, } } (*(entry))->rule_id = id; + (*(entry))->ipacm_installed = user; return 0; @@ -1012,7 +1013,7 @@ ipa_insert_failed: static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, const struct ipa_rt_rule *rule, u8 at_rear, u32 *rule_hdl, - u16 rule_id) + u16 rule_id, bool user) { struct ipa3_rt_tbl *tbl; struct ipa3_rt_entry *entry; @@ -1041,7 +1042,7 @@ static int __ipa_add_rt_rule(enum ipa_ip_type ip, const char *name, } if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx, - rule_id)) + rule_id, user)) goto error; if (at_rear) @@ -1072,7 +1073,7 @@ static int __ipa_add_rt_rule_after(struct ipa3_rt_tbl *tbl, if (__ipa_rt_validate_hndls(rule, &hdr, &proc_ctx)) goto error; - if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx, 0)) + if (__ipa_create_rt_entry(&entry, rule, tbl, hdr, proc_ctx, 0, true)) goto error; list_add(&entry->link, &((*add_after_entry)->link)); @@ -1101,8 +1102,24 @@ error: * * Note: Should not be called from atomic context */ + int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) { + return ipa3_add_rt_rule_usr(rules, false); +} +/** + * ipa3_add_rt_rule_usr() - Add the specified routing rules to SW and optionally + * commit to IPA HW + * @rules: [inout] set of routing rules to add + * @user_only: [in] indicate installed by userspace module + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ + +int ipa3_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, bool user_only) +{ int i; int ret; @@ -1117,7 +1134,8 @@ int ipa3_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) &rules->rules[i].rule, rules->rules[i].at_rear, &rules->rules[i].rt_rule_hdl, - 0)) { + 0, + user_only)) { IPAERR("failed to add rt rule %d\n", i); rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED; } else { @@ -1162,7 +1180,7 @@ int ipa3_add_rt_rule_ext(struct ipa_ioc_add_rt_rule_ext *rules) &rules->rules[i].rule, rules->rules[i].at_rear, &rules->rules[i].rt_rule_hdl, - rules->rules[i].rule_id)) { + rules->rules[i].rule_id, true)) { IPAERR("failed to add rt rule %d\n", i); rules->rules[i].status = IPA_RT_STATUS_OF_ADD_FAILED; } else { @@ -1439,13 +1457,14 @@ bail: /** * ipa3_reset_rt() - reset the current SW routing table of specified type * (does not commit to HW) - * @ip: The family of routing tables + * @ip: [in] The family of routing tables + * @user_only: [in] indicate delete rules installed by userspace * * Returns: 0 on success, negative on failure * * Note: Should not be called from atomic context */ -int ipa3_reset_rt(enum ipa_ip_type ip) +int ipa3_reset_rt(enum ipa_ip_type ip, bool user_only) { struct ipa3_rt_tbl *tbl; struct ipa3_rt_tbl *tbl_next; @@ -1455,6 +1474,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip) struct ipa3_rt_tbl_set *rset; u32 apps_start_idx; int id; + bool tbl_user = false; if (ip >= IPA_IP_MAX) { IPAERR_RL("bad parm\n"); @@ -1472,7 +1492,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip) * issue a reset on the filtering module of same IP type since * filtering rules point to routing tables */ - if (ipa3_reset_flt(ip)) + if (ipa3_reset_flt(ip, user_only)) IPAERR_RL("fail to reset flt ip=%d\n", ip); set = &ipa3_ctx->rt_tbl_set[ip]; @@ -1480,6 +1500,7 @@ int ipa3_reset_rt(enum ipa_ip_type ip) mutex_lock(&ipa3_ctx->lock); IPADBG("reset rt ip=%d\n", ip); list_for_each_entry_safe(tbl, tbl_next, &set->head_rt_tbl_list, link) { + tbl_user = false; list_for_each_entry_safe(rule, rule_next, &tbl->head_rt_rule_list, link) { if (ipa3_id_find(rule->id) == NULL) { @@ -1488,6 +1509,12 @@ int ipa3_reset_rt(enum ipa_ip_type ip) return -EFAULT; } + /* indicate if tbl used for user-specified rules*/ + if (rule->ipacm_installed) { + IPADBG("tbl_user %d, tbl-index %d\n", + tbl_user, tbl->id); + tbl_user = true; + } /* * for the "default" routing tbl, remove all but the * last rule @@ -1495,19 +1522,23 @@ int ipa3_reset_rt(enum ipa_ip_type ip) if (tbl->idx == apps_start_idx && tbl->rule_cnt == 1) continue; - list_del(&rule->link); - tbl->rule_cnt--; - if (rule->hdr) - __ipa3_release_hdr(rule->hdr->id); - else if (rule->proc_ctx) - __ipa3_release_hdr_proc_ctx(rule->proc_ctx->id); - rule->cookie = 0; - idr_remove(&tbl->rule_ids, rule->rule_id); - id = rule->id; - kmem_cache_free(ipa3_ctx->rt_rule_cache, rule); - - /* remove the handle from the database */ - ipa3_id_remove(id); + if (!user_only || + rule->ipacm_installed) { + list_del(&rule->link); + tbl->rule_cnt--; + if (rule->hdr) + __ipa3_release_hdr(rule->hdr->id); + else if (rule->proc_ctx) + __ipa3_release_hdr_proc_ctx( + rule->proc_ctx->id); + rule->cookie = 0; + idr_remove(&tbl->rule_ids, rule->rule_id); + id = rule->id; + kmem_cache_free(ipa3_ctx->rt_rule_cache, rule); + + /* remove the handle from the database */ + ipa3_id_remove(id); + } } if (ipa3_id_find(tbl->id) == NULL) { @@ -1519,26 +1550,30 @@ int ipa3_reset_rt(enum ipa_ip_type ip) /* do not remove the "default" routing tbl which has index 0 */ if (tbl->idx != apps_start_idx) { - idr_destroy(&tbl->rule_ids); - if (tbl->in_sys[IPA_RULE_HASHABLE] || - tbl->in_sys[IPA_RULE_NON_HASHABLE]) { - list_move(&tbl->link, &rset->head_rt_tbl_list); - clear_bit(tbl->idx, + if (!user_only || tbl_user) { + idr_destroy(&tbl->rule_ids); + if (tbl->in_sys[IPA_RULE_HASHABLE] || + tbl->in_sys[IPA_RULE_NON_HASHABLE]) { + list_move(&tbl->link, + &rset->head_rt_tbl_list); + clear_bit(tbl->idx, &ipa3_ctx->rt_idx_bitmap[ip]); - set->tbl_cnt--; - IPADBG("rst sys rt tbl_idx=%d tbl_cnt=%d\n", + set->tbl_cnt--; + IPADBG("rst tbl_idx=%d cnt=%d\n", tbl->idx, set->tbl_cnt); - } else { - list_del(&tbl->link); - set->tbl_cnt--; - clear_bit(tbl->idx, + } else { + list_del(&tbl->link); + set->tbl_cnt--; + clear_bit(tbl->idx, &ipa3_ctx->rt_idx_bitmap[ip]); - IPADBG("rst rt tbl_idx=%d tbl_cnt=%d\n", + IPADBG("rst rt tbl_idx=%d tbl_cnt=%d\n", tbl->idx, set->tbl_cnt); - kmem_cache_free(ipa3_ctx->rt_tbl_cache, tbl); + kmem_cache_free(ipa3_ctx->rt_tbl_cache, + tbl); + } + /* remove the handle from the database */ + ipa3_id_remove(id); } - /* remove the handle from the database */ - ipa3_id_remove(id); } } mutex_unlock(&ipa3_ctx->lock); @@ -1653,6 +1688,7 @@ static int __ipa_mdfy_rt_rule(struct ipa_rt_rule_mdfy *rtrule) struct ipa3_hdr_proc_ctx_entry *proc_ctx = NULL; struct ipa3_hdr_entry *hdr_entry; struct ipa3_hdr_proc_ctx_entry *hdr_proc_entry; + if (rtrule->rule.hdr_hdl) { hdr = ipa3_id_find(rtrule->rule.hdr_hdl); if ((hdr == NULL) || (hdr->cookie != IPA_HDR_COOKIE)) { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 74176d1aa47a..f4bce295311c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -3153,6 +3153,7 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_cfg_ep_holb_by_client = ipa3_cfg_ep_holb_by_client; api_ctrl->ipa_cfg_ep_ctrl = ipa3_cfg_ep_ctrl; api_ctrl->ipa_add_hdr = ipa3_add_hdr; + api_ctrl->ipa_add_hdr_usr = ipa3_add_hdr_usr; api_ctrl->ipa_del_hdr = ipa3_del_hdr; api_ctrl->ipa_commit_hdr = ipa3_commit_hdr; api_ctrl->ipa_reset_hdr = ipa3_reset_hdr; @@ -3162,6 +3163,7 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_add_hdr_proc_ctx = ipa3_add_hdr_proc_ctx; api_ctrl->ipa_del_hdr_proc_ctx = ipa3_del_hdr_proc_ctx; api_ctrl->ipa_add_rt_rule = ipa3_add_rt_rule; + api_ctrl->ipa_add_rt_rule_usr = ipa3_add_rt_rule_usr; api_ctrl->ipa_del_rt_rule = ipa3_del_rt_rule; api_ctrl->ipa_commit_rt = ipa3_commit_rt; api_ctrl->ipa_reset_rt = ipa3_reset_rt; @@ -3170,6 +3172,7 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_query_rt_index = ipa3_query_rt_index; api_ctrl->ipa_mdfy_rt_rule = ipa3_mdfy_rt_rule; api_ctrl->ipa_add_flt_rule = ipa3_add_flt_rule; + api_ctrl->ipa_add_flt_rule_usr = ipa3_add_flt_rule_usr; api_ctrl->ipa_del_flt_rule = ipa3_del_flt_rule; api_ctrl->ipa_mdfy_flt_rule = ipa3_mdfy_flt_rule; api_ctrl->ipa_commit_flt = ipa3_commit_flt; diff --git a/include/linux/ipa.h b/include/linux/ipa.h index a4b817c5e4fc..623d0f08cdf9 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. +/* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1226,11 +1226,13 @@ int ipa_cfg_ep_ctrl(u32 clnt_hdl, const struct ipa_ep_cfg_ctrl *ep_ctrl); */ int ipa_add_hdr(struct ipa_ioc_add_hdr *hdrs); +int ipa_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, bool user_only); + int ipa_del_hdr(struct ipa_ioc_del_hdr *hdls); int ipa_commit_hdr(void); -int ipa_reset_hdr(void); +int ipa_reset_hdr(bool user_only); int ipa_get_hdr(struct ipa_ioc_get_hdr *lookup); @@ -1241,7 +1243,8 @@ int ipa_copy_hdr(struct ipa_ioc_copy_hdr *copy); /* * Header Processing Context */ -int ipa_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs); +int ipa_add_hdr_proc_ctx(struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs, + bool user_only); int ipa_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls); @@ -1250,11 +1253,13 @@ int ipa_del_hdr_proc_ctx(struct ipa_ioc_del_hdr_proc_ctx *hdls); */ int ipa_add_rt_rule(struct ipa_ioc_add_rt_rule *rules); +int ipa_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, bool user_only); + int ipa_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls); int ipa_commit_rt(enum ipa_ip_type ip); -int ipa_reset_rt(enum ipa_ip_type ip); +int ipa_reset_rt(enum ipa_ip_type ip, bool user_only); int ipa_get_rt_tbl(struct ipa_ioc_get_rt_tbl *lookup); @@ -1269,13 +1274,15 @@ int ipa_mdfy_rt_rule(struct ipa_ioc_mdfy_rt_rule *rules); */ int ipa_add_flt_rule(struct ipa_ioc_add_flt_rule *rules); +int ipa_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, bool user_only); + int ipa_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls); int ipa_mdfy_flt_rule(struct ipa_ioc_mdfy_flt_rule *rules); int ipa_commit_flt(enum ipa_ip_type ip); -int ipa_reset_flt(enum ipa_ip_type ip); +int ipa_reset_flt(enum ipa_ip_type ip, bool user_only); /* * NAT @@ -1648,6 +1655,12 @@ static inline int ipa_add_hdr(struct ipa_ioc_add_hdr *hdrs) return -EPERM; } +static inline int ipa_add_hdr_usr(struct ipa_ioc_add_hdr *hdrs, + bool user_only) +{ + return -EPERM; +} + static inline int ipa_del_hdr(struct ipa_ioc_del_hdr *hdls) { return -EPERM; @@ -1658,7 +1671,7 @@ static inline int ipa_commit_hdr(void) return -EPERM; } -static inline int ipa_reset_hdr(void) +static inline int ipa_reset_hdr(bool user_only) { return -EPERM; } @@ -1682,7 +1695,8 @@ static inline int ipa_copy_hdr(struct ipa_ioc_copy_hdr *copy) * Header Processing Context */ static inline int ipa_add_hdr_proc_ctx( - struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs) + struct ipa_ioc_add_hdr_proc_ctx *proc_ctxs, + bool user_only) { return -EPERM; } @@ -1699,6 +1713,12 @@ static inline int ipa_add_rt_rule(struct ipa_ioc_add_rt_rule *rules) return -EPERM; } +static inline int ipa_add_rt_rule_usr(struct ipa_ioc_add_rt_rule *rules, + bool user_only) +{ + return -EPERM; +} + static inline int ipa_del_rt_rule(struct ipa_ioc_del_rt_rule *hdls) { return -EPERM; @@ -1709,7 +1729,7 @@ static inline int ipa_commit_rt(enum ipa_ip_type ip) return -EPERM; } -static inline int ipa_reset_rt(enum ipa_ip_type ip) +static inline int ipa_reset_rt(enum ipa_ip_type ip, bool user_only) { return -EPERM; } @@ -1742,6 +1762,12 @@ static inline int ipa_add_flt_rule(struct ipa_ioc_add_flt_rule *rules) return -EPERM; } +static inline int ipa_add_flt_rule_usr(struct ipa_ioc_add_flt_rule *rules, + bool user_only) +{ + return -EPERM; +} + static inline int ipa_del_flt_rule(struct ipa_ioc_del_flt_rule *hdls) { return -EPERM; @@ -1757,7 +1783,7 @@ static inline int ipa_commit_flt(enum ipa_ip_type ip) return -EPERM; } -static inline int ipa_reset_flt(enum ipa_ip_type ip) +static inline int ipa_reset_flt(enum ipa_ip_type ip, bool user_only) { return -EPERM; } diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 001ef390e288..33090dd4489f 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -95,7 +95,9 @@ #define IPA_IOCTL_DEL_VLAN_IFACE 53 #define IPA_IOCTL_ADD_L2TP_VLAN_MAPPING 54 #define IPA_IOCTL_DEL_L2TP_VLAN_MAPPING 55 -#define IPA_IOCTL_MAX 56 +#define IPA_IOCTL_CLEANUP 56 +#define IPA_IOCTL_QUERY_WLAN_CLIENT 57 +#define IPA_IOCTL_MAX 58 /** * max size of the header to be inserted @@ -1912,6 +1914,10 @@ struct ipa_tether_device_info { #define IPA_IOC_DEL_L2TP_VLAN_MAPPING _IOWR(IPA_IOC_MAGIC, \ IPA_IOCTL_DEL_L2TP_VLAN_MAPPING, \ struct ipa_ioc_l2tp_vlan_mapping_info *) +#define IPA_IOC_CLEANUP _IO(IPA_IOC_MAGIC,\ + IPA_IOCTL_CLEANUP) +#define IPA_IOC_QUERY_WLAN_CLIENT _IO(IPA_IOC_MAGIC,\ + IPA_IOCTL_QUERY_WLAN_CLIENT) /* * unique magic number of the Tethering bridge ioctls */