diff options
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_api.c | 18 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_api.h | 2 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_v2/ipa_client.c | 114 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_v2/ipa_i.h | 6 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_v2/ipa_utils.c | 1 | ||||
| -rw-r--r-- | drivers/platform/msm/ipa/ipa_v3/ipa_utils.c | 1 | ||||
| -rw-r--r-- | include/linux/ipa.h | 13 |
7 files changed, 140 insertions, 15 deletions
diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 208a4ce1e40e..7a9307294a6d 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -369,6 +369,24 @@ 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 +*/ +int ipa_disable_endpoint(u32 clnt_hdl) +{ + int ret; + + IPA_API_DISPATCH_RETURN(ipa_disable_endpoint, clnt_hdl); + + return ret; +} +EXPORT_SYMBOL(ipa_disable_endpoint); + /** * ipa_cfg_ep - IPA end-point configuration diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h index 862bdc475025..3c2471dd11dd 100644 --- a/drivers/platform/msm/ipa/ipa_api.h +++ b/drivers/platform/msm/ipa/ipa_api.h @@ -26,6 +26,8 @@ struct ipa_api_controller { int (*ipa_clear_endpoint_delay)(u32 clnt_hdl); + int (*ipa_disable_endpoint)(u32 clnt_hdl); + int (*ipa_cfg_ep)(u32 clnt_hdl, const struct ipa_ep_cfg *ipa_ep_cfg); int (*ipa_cfg_ep_nat)(u32 clnt_hdl, diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_client.c b/drivers/platform/msm/ipa/ipa_v2/ipa_client.c index 64246ac4eec0..66e329a03df7 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_client.c @@ -560,22 +560,30 @@ int ipa2_disconnect(u32 clnt_hdl) if (!ep->keep_ipa_awake) IPA_ACTIVE_CLIENTS_INC_EP(client_type); - /* Set Disconnect in Progress flag. */ - spin_lock(&ipa_ctx->disconnect_lock); - ep->disconnect_in_progress = true; - spin_unlock(&ipa_ctx->disconnect_lock); - - /* Notify uc to stop monitoring holb on USB BAM Producer pipe. */ - if (IPA_CLIENT_IS_USB_CONS(ep->client)) { - ipa_uc_monitor_holb(ep->client, false); - IPADBG("Disabling holb monitor for client: %d\n", ep->client); - } + /* For USB 2.0 controller, first the ep will be disabled. + * so this sequence is not needed again when disconnecting the pipe. + */ + if (!ep->ep_disabled) { + /* Set Disconnect in Progress flag. */ + spin_lock(&ipa_ctx->disconnect_lock); + ep->disconnect_in_progress = true; + spin_unlock(&ipa_ctx->disconnect_lock); + + /* Notify uc to stop monitoring holb on USB BAM + * Producer pipe. + */ + if (IPA_CLIENT_IS_USB_CONS(ep->client)) { + ipa_uc_monitor_holb(ep->client, false); + IPADBG("Disabling holb monitor for client: %d\n", + ep->client); + } - result = ipa_disable_data_path(clnt_hdl); - if (result) { - IPAERR("disable data path failed res=%d clnt=%d.\n", result, - clnt_hdl); - return -EPERM; + result = ipa_disable_data_path(clnt_hdl); + if (result) { + IPAERR("disable data path failed res=%d clnt=%d.\n", + result, clnt_hdl); + return -EPERM; + } } result = sps_disconnect(ep->ep_hdl); @@ -784,6 +792,82 @@ int ipa2_clear_endpoint_delay(u32 clnt_hdl) } /** + * ipa2_disable_endpoint() - low-level IPA client disable endpoint + * @clnt_hdl: [in] opaque client handle assigned by IPA to client + * + * Should be called by the driver of the peripheral that wants to + * disable the pipe from IPA in BAM-BAM mode. + * + * Returns: 0 on success, negative on failure + * + * Note: Should not be called from atomic context + */ +int ipa2_disable_endpoint(u32 clnt_hdl) +{ + int result; + struct ipa_ep_context *ep; + enum ipa_client_type client_type; + unsigned long bam; + + if (unlikely(!ipa_ctx)) { + IPAERR("IPA driver was not initialized\n"); + return -EINVAL; + } + + if (clnt_hdl >= ipa_ctx->ipa_num_pipes || + ipa_ctx->ep[clnt_hdl].valid == 0) { + IPAERR("bad parm.\n"); + return -EINVAL; + } + + ep = &ipa_ctx->ep[clnt_hdl]; + client_type = ipa2_get_client_mapping(clnt_hdl); + IPA_ACTIVE_CLIENTS_INC_EP(client_type); + + /* Set Disconnect in Progress flag. */ + spin_lock(&ipa_ctx->disconnect_lock); + ep->disconnect_in_progress = true; + spin_unlock(&ipa_ctx->disconnect_lock); + + /* Notify uc to stop monitoring holb on USB BAM Producer pipe. */ + if (IPA_CLIENT_IS_USB_CONS(ep->client)) { + ipa_uc_monitor_holb(ep->client, false); + IPADBG("Disabling holb monitor for client: %d\n", ep->client); + } + + result = ipa_disable_data_path(clnt_hdl); + if (result) { + IPAERR("disable data path failed res=%d clnt=%d.\n", result, + clnt_hdl); + goto fail; + } + + if (IPA_CLIENT_IS_CONS(ep->client)) + bam = ep->connect.source; + else + bam = ep->connect.destination; + + result = sps_pipe_reset(bam, clnt_hdl); + if (result) { + IPAERR("SPS pipe reset failed.\n"); + goto fail; + } + + ep->ep_disabled = true; + + IPA_ACTIVE_CLIENTS_DEC_EP(client_type); + + IPADBG("client (ep: %d) disabled\n", clnt_hdl); + + return 0; + +fail: + IPA_ACTIVE_CLIENTS_DEC_EP(client_type); + return -EPERM; +} + + +/** * ipa_sps_connect_safe() - connect endpoint from BAM prespective * @h: [in] sps pipe handle * @connect: [in] sps connect parameters diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h index 0a0b23815ce3..a8d68f27af18 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_i.h @@ -553,6 +553,7 @@ struct ipa_ep_context { bool switch_to_intr; int inactive_cycles; u32 eot_in_poll_err; + bool ep_disabled; /* sys MUST be the last element of this struct */ struct ipa_sys_context *sys; @@ -1431,6 +1432,11 @@ int ipa2_reset_endpoint(u32 clnt_hdl); int ipa2_clear_endpoint_delay(u32 clnt_hdl); /* + * Disable ep + */ +int ipa2_disable_endpoint(u32 clnt_hdl); + +/* * Configuration */ int ipa2_cfg_ep(u32 clnt_hdl, const struct ipa_ep_cfg *ipa_ep_cfg); diff --git a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c index 69052eb289bb..1d88082352c6 100644 --- a/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v2/ipa_utils.c @@ -4949,6 +4949,7 @@ int ipa2_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_disconnect = ipa2_disconnect; api_ctrl->ipa_reset_endpoint = ipa2_reset_endpoint; api_ctrl->ipa_clear_endpoint_delay = ipa2_clear_endpoint_delay; + api_ctrl->ipa_disable_endpoint = ipa2_disable_endpoint; api_ctrl->ipa_cfg_ep = ipa2_cfg_ep; api_ctrl->ipa_cfg_ep_nat = ipa2_cfg_ep_nat; api_ctrl->ipa_cfg_ep_hdr = ipa2_cfg_ep_hdr; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c index 2c2708c4e2f3..5499eba92b1c 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c @@ -3046,6 +3046,7 @@ int ipa3_bind_api_controller(enum ipa_hw_type ipa_hw_type, api_ctrl->ipa_disconnect = ipa3_disconnect; api_ctrl->ipa_reset_endpoint = ipa3_reset_endpoint; api_ctrl->ipa_clear_endpoint_delay = ipa3_clear_endpoint_delay; + api_ctrl->ipa_disable_endpoint = NULL; api_ctrl->ipa_cfg_ep = ipa3_cfg_ep; api_ctrl->ipa_cfg_ep_nat = ipa3_cfg_ep_nat; api_ctrl->ipa_cfg_ep_hdr = ipa3_cfg_ep_hdr; diff --git a/include/linux/ipa.h b/include/linux/ipa.h index d152057af385..5f85508353c9 100644 --- a/include/linux/ipa.h +++ b/include/linux/ipa.h @@ -1096,6 +1096,11 @@ int ipa_reset_endpoint(u32 clnt_hdl); int ipa_clear_endpoint_delay(u32 clnt_hdl); /* + * Disable ep + */ +int ipa_disable_endpoint(u32 clnt_hdl); + +/* * Configuration */ int ipa_cfg_ep(u32 clnt_hdl, const struct ipa_ep_cfg *ipa_ep_cfg); @@ -1462,6 +1467,14 @@ static inline int ipa_clear_endpoint_delay(u32 clnt_hdl) } /* + * Disable ep + */ +static inline int ipa_disable_endpoint(u32 clnt_hdl) +{ + return -EPERM; +} + +/* * Configuration */ static inline int ipa_cfg_ep(u32 clnt_hdl, |
