From 68766e4fe57bbf54240b6d3b8c90890cc6e330ff Mon Sep 17 00:00:00 2001 From: Gidon Studinski <gidons@codeaurora.org> Date: Fri, 14 Mar 2014 08:24:30 +0200 Subject: [PATCH] msm: ipa: add support for power save Adds support for power save feature in IPA driver. IPA clocks will be gated when there are no clients connected to IPA. Change-Id: I401cb84185c8c91e79f18a5baea340b644186298 Signed-off-by: Gidon Studinski <gidons@codeaurora.org> --- drivers/platform/msm/ipa/ipa.c | 27 +++ drivers/platform/msm/ipa/ipa_client.c | 112 ++++------ drivers/platform/msm/ipa/ipa_debugfs.c | 2 - drivers/platform/msm/ipa/ipa_dp.c | 25 ++- drivers/platform/msm/ipa/ipa_i.h | 19 +- drivers/platform/msm/ipa/ipa_utils.c | 295 ++++++++++++++++++++++++- include/linux/ipa.h | 15 +- 7 files changed, 395 insertions(+), 100 deletions(-) diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c index 5639447ea335..5c185c8d181d 100644 --- a/drivers/platform/msm/ipa/ipa.c +++ b/drivers/platform/msm/ipa/ipa.c @@ -1597,6 +1597,33 @@ void ipa_inc_client_enable_clks(void) mutex_unlock(&ipa_ctx->ipa_active_clients_lock); } +/** +* ipa_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 ipa_inc_client_enable_clks_no_block(void) +{ + int res = 0; + + if (mutex_trylock(&ipa_ctx->ipa_active_clients_lock) == 0) + return -EPERM; + if (ipa_ctx->ipa_active_clients == 0) { + res = -EPERM; + goto bail; + } + + ipa_ctx->ipa_active_clients++; + IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients); +bail: + mutex_unlock(&ipa_ctx->ipa_active_clients_lock); + + return res; +} + /** * ipa_dec_client_disable_clks() - Decrease active clients counter, and * disable ipa clocks if necessary diff --git a/drivers/platform/msm/ipa/ipa_client.c b/drivers/platform/msm/ipa/ipa_client.c index d6b531392175..031cf421bfbe 100644 --- a/drivers/platform/msm/ipa/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_client.c @@ -44,10 +44,15 @@ int ipa_enable_data_path(u32 clnt_hdl) } /* Enable the pipe */ - memset(&ep_cfg_ctrl, 0 , sizeof(ep_cfg_ctrl)); - ep_cfg_ctrl.ipa_ep_suspend = false; - - ipa_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); + if (IPA_CLIENT_IS_CONS(ep->client) && + (ep->keep_ipa_awake || + ep->resume_on_connect || + !ipa_should_pipe_be_suspended(ep->client))) { + memset(&ep_cfg_ctrl, 0 , sizeof(ep_cfg_ctrl)); + ep_cfg_ctrl.ipa_ep_suspend = false; + ipa_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); + ep->resume_on_connect = false; + } return res; } @@ -74,10 +79,11 @@ int ipa_disable_data_path(u32 clnt_hdl) } /* Suspend the pipe */ - memset(&ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl)); - ep_cfg_ctrl.ipa_ep_suspend = true; - - ipa_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); + if (IPA_CLIENT_IS_CONS(ep->client)) { + memset(&ep_cfg_ctrl, 0 , sizeof(struct ipa_ep_cfg_ctrl)); + ep_cfg_ctrl.ipa_ep_suspend = true; + ipa_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl); + } udelay(IPA_PKT_FLUSH_TO_US); if (IPA_CLIENT_IS_CONS(ep->client) && @@ -222,6 +228,7 @@ int ipa_connect(const struct ipa_connect_params *in, struct ipa_sps_params *sps, ep->client = in->client; ep->client_notify = in->notify; ep->priv = in->priv; + ep->keep_ipa_awake = in->keep_ipa_awake; result = ipa_enable_data_path(ipa_ep_idx); if (result) { @@ -302,7 +309,11 @@ int ipa_connect(const struct ipa_connect_params *in, struct ipa_sps_params *sps, if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(in->client)) ipa_install_dflt_flt_rules(ipa_ep_idx); + if (!ep->keep_ipa_awake) + ipa_dec_client_disable_clks(); + ipa_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg; + IPADBG("client %d (ep: %d) connected\n", in->client, ipa_ep_idx); return 0; @@ -361,10 +372,8 @@ int ipa_disconnect(u32 clnt_hdl) ep = &ipa_ctx->ep[clnt_hdl]; - if (ep->suspended) { + if (!ep->keep_ipa_awake) ipa_inc_client_enable_clks(); - ep->suspended = false; - } result = ipa_disable_data_path(clnt_hdl); if (result) { @@ -422,79 +431,40 @@ int ipa_disconnect(u32 clnt_hdl) EXPORT_SYMBOL(ipa_disconnect); /** - * ipa_resume() - low-level IPA client resume - * @clnt_hdl: [in] opaque client handle assigned by IPA to client - * - * Should be called by the driver of the peripheral that wants to resume IPA - * connection. Resume IPA connection results in turning on IPA clocks in - * case they were off as a result of suspend. - * this api can be called only if a call to ipa_suspend() was - * made. - * - * Returns: 0 on success, negative on failure - * - * Note: Should not be called from atomic context - */ -int ipa_resume(u32 clnt_hdl) -{ - struct ipa_ep_context *ep; - - if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) { - IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl); - return -EINVAL; - } - - ep = &ipa_ctx->ep[clnt_hdl]; - - if (!ep->suspended) { - IPAERR("EP not suspended. clnt_hdl %d\n", clnt_hdl); - return -EPERM; - } - - ipa_inc_client_enable_clks(); - ep->suspended = false; - - return 0; -} -EXPORT_SYMBOL(ipa_resume); - -/** -* ipa_suspend() - low-level IPA client suspend -* @clnt_hdl: [in] opaque client handle assigned by IPA to client -* -* Should be called by the driver of the peripheral that wants to suspend IPA -* connection. Suspend IPA connection results in turning off IPA clocks in -* case that there is no active clients using IPA. Pipes remains connected in -* case of suspend. +* 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_suspend(u32 clnt_hdl) +int ipa_reset_endpoint(u32 clnt_hdl) { + int res; struct ipa_ep_context *ep; - if (clnt_hdl >= IPA_NUM_PIPES || ipa_ctx->ep[clnt_hdl].valid == 0) { - IPAERR("bad parm. clnt_hdl %d\n", clnt_hdl); - return -EINVAL; + if (clnt_hdl < 0 || clnt_hdl >= IPA_CLIENT_MAX) { + IPAERR("Bad parameters.\n"); + return -EFAULT; } - ep = &ipa_ctx->ep[clnt_hdl]; - if (ep->suspended) { - IPAERR("EP already suspended. clnt_hdl %d\n", clnt_hdl); - return -EPERM; + ipa_inc_client_enable_clks(); + res = sps_disconnect(ep->ep_hdl); + if (res) { + IPAERR("sps_disconnect() failed, res=%d.\n", res); + goto bail; + } else { + res = sps_connect(ep->ep_hdl, &ep->connect); + if (res) { + IPAERR("sps_connect() failed, res=%d.\n", res); + goto bail; + } } - if (IPA_CLIENT_IS_CONS(ep->client) && - ep->cfg.aggr.aggr_en == IPA_ENABLE_AGGR && - ep->cfg.aggr.aggr_time_limit) - msleep(ep->cfg.aggr.aggr_time_limit); - +bail: ipa_dec_client_disable_clks(); - ep->suspended = true; - return 0; + return res; } -EXPORT_SYMBOL(ipa_suspend); +EXPORT_SYMBOL(ipa_reset_endpoint); diff --git a/drivers/platform/msm/ipa/ipa_debugfs.c b/drivers/platform/msm/ipa/ipa_debugfs.c index 7381a32db226..37aa78156898 100644 --- a/drivers/platform/msm/ipa/ipa_debugfs.c +++ b/drivers/platform/msm/ipa/ipa_debugfs.c @@ -624,7 +624,6 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, { int i; int j; - int k; struct ipa_flt_tbl *tbl; struct ipa_flt_entry *entry; enum ipa_ip_type ip = (enum ipa_ip_type)file->private_data; @@ -681,7 +680,6 @@ static ssize_t ipa_read_flt(struct file *file, char __user *ubuf, size_t count, bitmap = entry->rule.attrib.attrib_mask; eq = false; } - k = ipa_get_client_mapping(j); pr_info( "ep_idx:%d rule_idx:%d act:%d rt_tbl_idx:%d " "attrib_mask:%08x to_uc:%d, retain_hdr:%d eq:%d ", diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c index c557ca28e113..29a408b9b315 100644 --- a/drivers/platform/msm/ipa/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_dp.c @@ -922,26 +922,33 @@ int ipa_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) ep = &ipa_ctx->ep[ipa_ep_idx]; + ipa_inc_client_enable_clks(); + if (ep->valid == 1) { if (sys_in->client != IPA_CLIENT_APPS_LAN_WAN_PROD) { IPAERR("EP already allocated.\n"); - goto fail_gen; + goto fail_and_disable_clocks; } else { if (ipa_cfg_ep_hdr(ipa_ep_idx, &sys_in->ipa_ep_cfg.hdr)) { IPAERR("fail to configure hdr prop of EP.\n"); - return -EFAULT; + result = -EFAULT; + goto fail_and_disable_clocks; } if (ipa_cfg_ep_cfg(ipa_ep_idx, &sys_in->ipa_ep_cfg.cfg)) { IPAERR("fail to configure cfg prop of EP.\n"); - return -EFAULT; + result = -EFAULT; + goto fail_and_disable_clocks; } IPADBG("client %d (ep: %d) overlay ok sys=%p\n", sys_in->client, ipa_ep_idx, ep->sys); ep->client_notify = sys_in->notify; ep->priv = sys_in->priv; *clnt_hdl = ipa_ep_idx; + if (!ep->keep_ipa_awake) + ipa_dec_client_disable_clks(); + return 0; } } @@ -952,7 +959,7 @@ int ipa_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) if (!ep->sys) { IPAERR("failed to sys ctx for client %d\n", sys_in->client); result = -ENOMEM; - goto fail_gen; + goto fail_and_disable_clocks; } snprintf(buff, IPA_RESOURCE_NAME_MAX, "ipawq%d", sys_in->client); @@ -975,6 +982,7 @@ int ipa_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) ep->client = sys_in->client; ep->client_notify = sys_in->notify; ep->priv = sys_in->priv; + ep->keep_ipa_awake = sys_in->keep_ipa_awake; ep->avail_fifo_desc = ((sys_in->desc_fifo_sz/sizeof(struct sps_iovec))-1); INIT_LIST_HEAD(&ep->sys->head_desc_list); @@ -1081,6 +1089,9 @@ int ipa_setup_sys_pipe(struct ipa_sys_connect_params *sys_in, u32 *clnt_hdl) if (!ep->skip_ep_cfg && IPA_CLIENT_IS_PROD(sys_in->client)) ipa_install_dflt_flt_rules(ipa_ep_idx); + if (!ep->keep_ipa_awake) + ipa_dec_client_disable_clks(); + ipa_ctx->skip_ep_cfg_shadow[ipa_ep_idx] = ep->skip_ep_cfg; IPADBG("client %d (ep: %d) connected sys=%p\n", sys_in->client, ipa_ep_idx, ep->sys); @@ -1100,6 +1111,8 @@ fail_gen2: fail_wq: kfree(ep->sys); memset(&ipa_ctx->ep[ipa_ep_idx], 0, sizeof(struct ipa_ep_context)); +fail_and_disable_clocks: + ipa_dec_client_disable_clks(); fail_gen: return result; } @@ -1120,6 +1133,8 @@ int ipa_teardown_sys_pipe(u32 clnt_hdl) return -EINVAL; } + ipa_inc_client_enable_clks(); + ep = &ipa_ctx->ep[clnt_hdl]; if (IPA_CLIENT_IS_CONS(ep->client)) @@ -1136,6 +1151,8 @@ int ipa_teardown_sys_pipe(u32 clnt_hdl) ipa_delete_dflt_flt_rules(clnt_hdl); memset(ep, 0, sizeof(struct ipa_ep_context)); + ipa_dec_client_disable_clks(); + IPADBG("client (ep: %d) disconnected\n", clnt_hdl); return 0; diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h index 024a9e890339..0e5e23d6ef97 100644 --- a/drivers/platform/msm/ipa/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_i.h @@ -124,6 +124,12 @@ (((start_ofst) + 127) & ~127) #define IPA_RT_FLT_HW_RULE_BUF_SIZE (128) +#define MAX_RESOURCE_TO_CLIENTS (5) +struct ipa_client_names { + enum ipa_client_type names[MAX_RESOURCE_TO_CLIENTS]; + int length; +}; + /** * struct ipa_mem_buffer - IPA memory buffer * @base: base @@ -322,7 +328,6 @@ struct ipa_ep_cfg_status { * @data_fifo_pipe_mem_ofst: data FIFO pipe memory offset * @desc_fifo_client_allocated: if descriptors FIFO was allocated by a client * @data_fifo_client_allocated: if data FIFO was allocated by a client - * @suspended: valid for B2B pipes, whether IPA EP is suspended * @skip_ep_cfg: boolean field that determines if EP should be configured * by IPA driver * @keep_ipa_awake: when true, IPA will not be clock gated @@ -346,13 +351,13 @@ struct ipa_ep_context { u32 data_fifo_pipe_mem_ofst; bool desc_fifo_client_allocated; bool data_fifo_client_allocated; - bool suspended; struct ipa_sys_context *sys; u32 avail_fifo_desc; u32 dflt_flt4_rule_hdl; u32 dflt_flt6_rule_hdl; bool skip_ep_cfg; bool keep_ipa_awake; + bool resume_on_connect; }; enum ipa_sys_pipe_policy { @@ -818,7 +823,9 @@ int ipa_send_one(struct ipa_sys_context *sys, struct ipa_desc *desc, int ipa_send(struct ipa_sys_context *sys, u32 num_desc, struct ipa_desc *desc, bool in_atomic); int ipa_get_ep_mapping(enum ipa_client_type client); -int ipa_get_client_mapping(int pipe_idx); +enum ipa_client_type ipa_get_client_mapping(int pipe_idx); +enum ipa_rm_resource_name ipa_get_rm_resource_from_ep(int pipe_idx); + int ipa_generate_hw_rule(enum ipa_ip_type ip, const struct ipa_rule_attrib *attrib, u8 **buf, @@ -854,6 +861,7 @@ struct ipa_context *ipa_get_ctx(void); void ipa_enable_clks(void); void ipa_disable_clks(void); void ipa_inc_client_enable_clks(void); +int ipa_inc_client_enable_clks_no_block(void); void ipa_dec_client_disable_clks(void); int ipa_interrupts_init(u32 ipa_irq, u32 ee, struct device *ipa_dev); int __ipa_del_rt_rule(u32 rule_hdl); @@ -930,6 +938,9 @@ int ipa_set_required_perf_profile(enum ipa_voltage_level floor_voltage, int ipa_cfg_ep_status(u32 clnt_hdl, const struct ipa_ep_cfg_status *ipa_ep_cfg); - +int ipa_suspend_resource_no_block(enum ipa_rm_resource_name name); +int ipa_suspend_resource_sync(enum ipa_rm_resource_name name); +int ipa_resume_resource(enum ipa_rm_resource_name name); +bool ipa_should_pipe_be_suspended(enum ipa_client_type client); #endif /* _IPA_I_H_ */ diff --git a/drivers/platform/msm/ipa/ipa_utils.c b/drivers/platform/msm/ipa/ipa_utils.c index e2b426bf9eeb..f01cf0566ede 100644 --- a/drivers/platform/msm/ipa/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_utils.c @@ -223,6 +223,247 @@ static struct msm_bus_scale_pdata ipa_bus_client_pdata_v2_0 = { .name = "ipa", }; +/** + * ipa_get_clients_from_rm_resource() - get IPA clients which are related to an + * IPA_RM resource + * + * @resource: [IN] IPA Resource Manager resource + * @clients: [OUT] Empty array which will contain the list of clients. The + * caller must initialize this array. + * + * Return codes: 0 on success, negative on failure. + */ +int ipa_get_clients_from_rm_resource( + enum ipa_rm_resource_name resource, + struct ipa_client_names *clients) +{ + int i = 0; + + if (resource < 0 || + resource >= IPA_RM_RESOURCE_MAX || + !clients) { + IPAERR("Bad parameters\n"); + return -EINVAL; + } + + switch (resource) { + case IPA_RM_RESOURCE_USB_CONS: + clients->names[i++] = IPA_CLIENT_USB_CONS; + clients->names[i++] = IPA_CLIENT_USB2_CONS; + clients->names[i++] = IPA_CLIENT_USB3_CONS; + clients->names[i++] = IPA_CLIENT_USB4_CONS; + clients->length = i; + break; + case IPA_RM_RESOURCE_WLAN_CONS: + clients->names[i++] = IPA_CLIENT_WLAN1_CONS; + clients->names[i++] = IPA_CLIENT_WLAN2_CONS; + clients->names[i++] = IPA_CLIENT_WLAN3_CONS; + clients->names[i++] = IPA_CLIENT_WLAN4_CONS; + clients->length = i; + break; + default: + break; + } + + return 0; +} + +/** + * ipa_should_pipe_be_suspended() - returns true when the client's pipe should + * be suspended during a power save scenario. False otherwise. + * + * @client: [IN] IPA client + */ +bool ipa_should_pipe_be_suspended(enum ipa_client_type client) +{ + struct ipa_ep_context *ep; + int ipa_ep_idx; + + ipa_ep_idx = ipa_get_ep_mapping(client); + if (ipa_ep_idx == -1) { + IPAERR("Invalid client.\n"); + WARN_ON(1); + return false; + } + + ep = &ipa_ctx->ep[ipa_ep_idx]; + + if (ep->keep_ipa_awake) + return false; + + if (client == IPA_CLIENT_USB_CONS || + client == IPA_CLIENT_USB2_CONS || + client == IPA_CLIENT_USB3_CONS || + client == IPA_CLIENT_USB4_CONS || + client == IPA_CLIENT_WLAN1_CONS || + client == IPA_CLIENT_WLAN2_CONS || + client == IPA_CLIENT_WLAN3_CONS || + client == IPA_CLIENT_WLAN4_CONS) + return true; + + return false; +} + +/** + * ipa_suspend_resource_sync() - suspend client endpoints related to the IPA_RM + * resource and decrement active clients counter, which may result in clock + * gating of IPA clocks. + * + * @resource: [IN] IPA Resource Manager resource + * + * Return codes: 0 on success, negative on failure. + */ +int ipa_suspend_resource_sync(enum ipa_rm_resource_name resource) +{ + struct ipa_client_names clients; + int res; + int index; + struct ipa_ep_cfg_ctrl suspend; + enum ipa_client_type client; + int ipa_ep_idx; + bool pipe_suspended = false; + + memset(&clients, 0, sizeof(clients)); + res = ipa_get_clients_from_rm_resource(resource, &clients); + if (res) { + IPAERR("Bad params.\n"); + return res; + } + + for (index = 0; index < clients.length; index++) { + client = clients.names[index]; + ipa_ep_idx = ipa_get_ep_mapping(client); + if (ipa_ep_idx == -1) { + IPAERR("Invalid client.\n"); + res = -EINVAL; + continue; + } + if (ipa_should_pipe_be_suspended(client) && + ipa_ctx->ep[ipa_ep_idx].valid) { + /* suspend endpoint */ + memset(&suspend, 0, sizeof(suspend)); + suspend.ipa_ep_suspend = true; + ipa_cfg_ep_ctrl(ipa_ep_idx, &suspend); + pipe_suspended = true; + } + } + /* Sleep ~1 msec */ + if (pipe_suspended) + usleep_range(1000, 2000); + + ipa_dec_client_disable_clks(); + + return 0; +} + +/** + * 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 res; + struct ipa_client_names clients; + int index; + enum ipa_client_type client; + struct ipa_ep_cfg_ctrl suspend; + int ipa_ep_idx; + + if (mutex_trylock(&ipa_ctx->ipa_active_clients_lock) == 0) + return -EPERM; + if (ipa_ctx->ipa_active_clients == 1) { + res = -EPERM; + goto bail; + } + + memset(&clients, 0, sizeof(clients)); + res = ipa_get_clients_from_rm_resource(resource, &clients); + if (res) { + IPAERR("ipa_get_clients_from_rm_resource() failed, name = %d.\n" + , resource); + goto bail; + } + + for (index = 0; index < clients.length; index++) { + client = clients.names[index]; + ipa_ep_idx = ipa_get_ep_mapping(client); + if (ipa_ep_idx == -1) { + IPAERR("Invalid client.\n"); + res = -EINVAL; + continue; + } + if (ipa_should_pipe_be_suspended(client) && + ipa_ctx->ep[ipa_ep_idx].valid) { + /* suspend endpoint */ + memset(&suspend, 0, sizeof(suspend)); + suspend.ipa_ep_suspend = true; + ipa_cfg_ep_ctrl(ipa_ep_idx, &suspend); + } + } + + if (res == 0) { + ipa_ctx->ipa_active_clients--; + IPADBG("active clients = %d\n", ipa_ctx->ipa_active_clients); + } +bail: + mutex_unlock(&ipa_ctx->ipa_active_clients_lock); + + return res; +} + +/** + * ipa_resume_resource() - resume client endpoints related to the IPA_RM + * resource. + * + * @resource: [IN] IPA Resource Manager resource + * + * Return codes: 0 on success, negative on failure. + */ +int ipa_resume_resource(enum ipa_rm_resource_name resource) +{ + + struct ipa_client_names clients; + int res; + int index; + struct ipa_ep_cfg_ctrl suspend; + enum ipa_client_type client; + int ipa_ep_idx; + + memset(&clients, 0, sizeof(clients)); + res = ipa_get_clients_from_rm_resource(resource, &clients); + if (res) { + IPAERR("ipa_get_clients_from_rm_resource() failed.\n"); + return res; + } + + for (index = 0; index < clients.length; index++) { + client = clients.names[index]; + ipa_ep_idx = ipa_get_ep_mapping(client); + if (ipa_ep_idx == -1) { + IPAERR("Invalid client.\n"); + res = -EINVAL; + continue; + } + if (ipa_should_pipe_be_suspended(client)) { + if (ipa_ctx->ep[ipa_ep_idx].valid) { + memset(&suspend, 0, sizeof(suspend)); + suspend.ipa_ep_suspend = false; + ipa_cfg_ep_ctrl(ipa_ep_idx, &suspend); + } else { + ipa_ctx->ep[ipa_ep_idx].resume_on_connect = + true; + } + } + } + + return res; +} + /* read how much SRAM is available for SW use * In case of IPAv2.0 this will also supply an offset from * which we can start write @@ -430,7 +671,7 @@ int ipa_get_ep_mapping(enum ipa_client_type client) u8 hw_type_index = IPA_1_1; if (client >= IPA_CLIENT_MAX || client < 0) { - IPAERR("Bad client number!\n"); + IPAERR("Bad client number! client =%d\n", client); return -EINVAL; } @@ -442,30 +683,64 @@ int ipa_get_ep_mapping(enum ipa_client_type client) EXPORT_SYMBOL(ipa_get_ep_mapping); /** - * ipa_get_client_mapping() - provide client mapping - * @pipe_idx: IPA end-point number + * ipa_get_rm_resource_from_ep() - get the IPA_RM resource which is related to + * the supplied pipe index. * - * Return value: client mapping + * @pipe_idx: + * + * Return value: IPA_RM resource related to the pipe, -1 if a resource was not + * found. */ -int ipa_get_client_mapping(int pipe_idx) +enum ipa_rm_resource_name ipa_get_rm_resource_from_ep(int pipe_idx) { int i; - u8 hw_type_index = IPA_1_1; + int j; + enum ipa_client_type client; + struct ipa_client_names clients; + bool found = false; if (pipe_idx >= IPA_CLIENT_MAX || pipe_idx < 0) { IPAERR("Bad pipe index!\n"); return -EINVAL; } - if (ipa_ctx->ipa_hw_type == IPA_HW_v2_0) - hw_type_index = IPA_2_0; + client = ipa_ctx->ep[pipe_idx].client; - for (i = 0; i < IPA_CLIENT_MAX; i++) - if (ep_mapping[hw_type_index][i] == pipe_idx) + for (i = 0; i < IPA_RM_RESOURCE_MAX; i++) { + memset(&clients, 0, sizeof(clients)); + ipa_get_clients_from_rm_resource(i, &clients); + for (j = 0; j < clients.length; j++) { + if (clients.names[j] == client) { + found = true; + break; + } + } + if (found) break; + } + + if (!found) + return -EFAULT; + return i; } +/** + * ipa_get_client_mapping() - provide client mapping + * @pipe_idx: IPA end-point number + * + * Return value: client mapping + */ +enum ipa_client_type ipa_get_client_mapping(int pipe_idx) +{ + if (pipe_idx >= IPA_CLIENT_MAX || pipe_idx < 0) { + IPAERR("Bad pipe index!\n"); + return -EINVAL; + } + + return ipa_ctx->ep[pipe_idx].client; +} + /** * ipa_write_32() - convert 32 bit value to byte array * @w: 32 bit integer diff --git a/include/linux/ipa.h b/include/linux/ipa.h index 326e04223ce2..2a06f46cb5f5 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -403,6 +403,7 @@ typedef void (*ipa_notify_cb)(void *priv, enum ipa_dp_evt_type evt, * @data: data FIFO meta-data when client has allocated it * @skip_ep_cfg: boolean field that determines if EP should be configured * by IPA driver + * @keep_ipa_awake: when true, IPA will not be clock gated */ struct ipa_connect_params { struct ipa_ep_cfg ipa_ep_cfg; @@ -417,6 +418,7 @@ struct ipa_connect_params { struct sps_mem_buffer desc; struct sps_mem_buffer data; bool skip_ep_cfg; + bool keep_ipa_awake; }; /** @@ -482,6 +484,7 @@ struct ipa_ext_intf { * enum for valid cases. * @skip_ep_cfg: boolean field that determines if EP should be configured * by IPA driver + * @keep_ipa_awake: when true, IPA will not be clock gated */ struct ipa_sys_connect_params { struct ipa_ep_cfg ipa_ep_cfg; @@ -490,6 +493,7 @@ struct ipa_sys_connect_params { void *priv; ipa_notify_cb notify; bool skip_ep_cfg; + bool keep_ipa_awake; }; /** @@ -739,9 +743,7 @@ int ipa_disconnect(u32 clnt_hdl); /* * Resume / Suspend */ -int ipa_resume(u32 clnt_hdl); - -int ipa_suspend(u32 clnt_hdl); +int ipa_reset_endpoint(u32 clnt_hdl); /* * Configuration @@ -968,12 +970,7 @@ static inline int ipa_disconnect(u32 clnt_hdl) /* * Resume / Suspend */ -static inline int ipa_resume(u32 clnt_hdl) -{ - return -EPERM; -} - -static inline int ipa_suspend(u32 clnt_hdl) +static inline int ipa_reset_endpoint(u32 clnt_hdl) { return -EPERM; } -- GitLab