Loading drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +355 −144 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ enum ipa3_usb_state { IPA_USB_SUSPEND_REQUESTED, IPA_USB_SUSPEND_IN_PROGRESS, IPA_USB_SUSPENDED, IPA_USB_SUSPENDED_NO_RWAKEUP, IPA_USB_RESUME_IN_PROGRESS }; Loading @@ -152,6 +153,12 @@ struct finish_suspend_work_context { u32 ul_clnt_hdl; }; struct ipa3_usb_teth_prot_conn_params { u32 usb_to_ipa_clnt_hdl; u32 ipa_to_usb_clnt_hdl; struct ipa_usb_teth_prot_params params; }; /** * Transport type - could be either data tethering or DPL * Each transport has it's own RM resources and statuses Loading @@ -163,6 +170,7 @@ struct ipa3_usb_transport_type_ctx { enum ipa3_usb_state state; struct finish_suspend_work_context finish_suspend_work; struct ipa_usb_xdci_chan_params ch_params; struct ipa3_usb_teth_prot_conn_params teth_conn_params; }; struct ipa3_usb_smmu_reg_map { Loading @@ -189,14 +197,15 @@ struct ipa3_usb_context { }; enum ipa3_usb_op { IPA_USB_INIT_TETH_PROT, IPA_USB_REQUEST_CHANNEL, IPA_USB_CONNECT, IPA_USB_DISCONNECT, IPA_USB_RELEASE_CHANNEL, IPA_USB_DEINIT_TETH_PROT, IPA_USB_SUSPEND, IPA_USB_RESUME IPA_USB_OP_INIT_TETH_PROT, IPA_USB_OP_REQUEST_CHANNEL, IPA_USB_OP_CONNECT, IPA_USB_OP_DISCONNECT, IPA_USB_OP_RELEASE_CHANNEL, IPA_USB_OP_DEINIT_TETH_PROT, IPA_USB_OP_SUSPEND, IPA_USB_OP_SUSPEND_NO_RWAKEUP, IPA_USB_OP_RESUME }; struct ipa3_usb_status_dbg_info { Loading Loading @@ -228,22 +237,24 @@ struct ipa3_usb_context *ipa3_usb_ctx; static char *ipa3_usb_op_to_string(enum ipa3_usb_op op) { switch (op) { case IPA_USB_INIT_TETH_PROT: return "IPA_USB_INIT_TETH_PROT"; case IPA_USB_REQUEST_CHANNEL: return "IPA_USB_REQUEST_CHANNEL"; case IPA_USB_CONNECT: return "IPA_USB_CONNECT"; case IPA_USB_DISCONNECT: return "IPA_USB_DISCONNECT"; case IPA_USB_RELEASE_CHANNEL: return "IPA_USB_RELEASE_CHANNEL"; case IPA_USB_DEINIT_TETH_PROT: return "IPA_USB_DEINIT_TETH_PROT"; case IPA_USB_SUSPEND: return "IPA_USB_SUSPEND"; case IPA_USB_RESUME: return "IPA_USB_RESUME"; case IPA_USB_OP_INIT_TETH_PROT: return "IPA_USB_OP_INIT_TETH_PROT"; case IPA_USB_OP_REQUEST_CHANNEL: return "IPA_USB_OP_REQUEST_CHANNEL"; case IPA_USB_OP_CONNECT: return "IPA_USB_OP_CONNECT"; case IPA_USB_OP_DISCONNECT: return "IPA_USB_OP_DISCONNECT"; case IPA_USB_OP_RELEASE_CHANNEL: return "IPA_USB_OP_RELEASE_CHANNEL"; case IPA_USB_OP_DEINIT_TETH_PROT: return "IPA_USB_OP_DEINIT_TETH_PROT"; case IPA_USB_OP_SUSPEND: return "IPA_USB_OP_SUSPEND"; case IPA_USB_OP_SUSPEND_NO_RWAKEUP: return "IPA_USB_OP_SUSPEND_NO_RWAKEUP"; case IPA_USB_OP_RESUME: return "IPA_USB_OP_RESUME"; } return "UNSUPPORTED"; Loading @@ -266,6 +277,8 @@ static char *ipa3_usb_state_to_string(enum ipa3_usb_state state) return "IPA_USB_SUSPEND_IN_PROGRESS"; case IPA_USB_SUSPENDED: return "IPA_USB_SUSPENDED"; case IPA_USB_SUSPENDED_NO_RWAKEUP: return "IPA_USB_SUSPENDED_NO_RWAKEUP"; case IPA_USB_RESUME_IN_PROGRESS: return "IPA_USB_RESUME_IN_PROGRESS"; } Loading Loading @@ -312,6 +325,7 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit, if (state == IPA_USB_INITIALIZED || state == IPA_USB_STOPPED || state == IPA_USB_RESUME_IN_PROGRESS || state == IPA_USB_SUSPENDED_NO_RWAKEUP || /* * In case of failure during suspend request * handling, state is reverted to connected. Loading @@ -327,7 +341,8 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit, case IPA_USB_STOPPED: if (state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_CONNECTED || state == IPA_USB_SUSPENDED) state == IPA_USB_SUSPENDED || state == IPA_USB_SUSPENDED_NO_RWAKEUP) state_legal = true; break; case IPA_USB_SUSPEND_REQUESTED: Loading @@ -354,6 +369,10 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit, (err_permit && state == IPA_USB_RESUME_IN_PROGRESS)) state_legal = true; break; case IPA_USB_SUSPENDED_NO_RWAKEUP: if (state == IPA_USB_CONNECTED) state_legal = true; break; case IPA_USB_RESUME_IN_PROGRESS: if (state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_SUSPENDED) Loading Loading @@ -418,32 +437,33 @@ static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op, spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags); state = ipa3_usb_ctx->ttype_ctx[ttype].state; switch (op) { case IPA_USB_INIT_TETH_PROT: case IPA_USB_OP_INIT_TETH_PROT: if (state == IPA_USB_INVALID || (!is_dpl && state == IPA_USB_INITIALIZED)) is_legal = true; break; case IPA_USB_REQUEST_CHANNEL: case IPA_USB_OP_REQUEST_CHANNEL: if (state == IPA_USB_INITIALIZED) is_legal = true; break; case IPA_USB_CONNECT: case IPA_USB_OP_CONNECT: if (state == IPA_USB_INITIALIZED || state == IPA_USB_STOPPED) is_legal = true; break; case IPA_USB_DISCONNECT: case IPA_USB_OP_DISCONNECT: if (state == IPA_USB_CONNECTED || state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_SUSPENDED) state == IPA_USB_SUSPENDED || state == IPA_USB_SUSPENDED_NO_RWAKEUP) is_legal = true; break; case IPA_USB_RELEASE_CHANNEL: case IPA_USB_OP_RELEASE_CHANNEL: /* when releasing 1st channel state will be changed already */ if (state == IPA_USB_STOPPED || (!is_dpl && state == IPA_USB_INITIALIZED)) is_legal = true; break; case IPA_USB_DEINIT_TETH_PROT: case IPA_USB_OP_DEINIT_TETH_PROT: /* * For data tethering we should allow deinit an inited protocol * always. E.g. rmnet is inited and rndis is connected. Loading @@ -453,13 +473,18 @@ static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op, if (!is_dpl || state == IPA_USB_INITIALIZED) is_legal = true; break; case IPA_USB_SUSPEND: case IPA_USB_OP_SUSPEND: if (state == IPA_USB_CONNECTED) is_legal = true; break; case IPA_USB_RESUME: case IPA_USB_OP_SUSPEND_NO_RWAKEUP: if (state == IPA_USB_CONNECTED) is_legal = true; break; case IPA_USB_OP_RESUME: if (state == IPA_USB_SUSPENDED || state == IPA_USB_SUSPEND_IN_PROGRESS) state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_SUSPENDED_NO_RWAKEUP) is_legal = true; break; default: Loading Loading @@ -638,6 +663,7 @@ static int ipa3_usb_cons_request_resource_cb_do( ipa3_usb_ctx->ttype_ctx[ttype].state)); switch (ipa3_usb_ctx->ttype_ctx[ttype].state) { case IPA_USB_CONNECTED: case IPA_USB_SUSPENDED_NO_RWAKEUP: rm_ctx->cons_state = IPA_USB_CONS_GRANTED; result = 0; break; Loading Loading @@ -717,6 +743,7 @@ static int ipa3_usb_cons_release_resource_cb_do( break; case IPA_USB_STOPPED: case IPA_USB_RESUME_IN_PROGRESS: case IPA_USB_SUSPENDED_NO_RWAKEUP: if (rm_ctx->cons_requested) rm_ctx->cons_requested = false; break; Loading Loading @@ -886,7 +913,7 @@ int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_INIT_TETH_PROT, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_INIT_TETH_PROT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; Loading Loading @@ -1204,7 +1231,7 @@ static int ipa3_usb_request_xdci_channel( ttype = IPA3_USB_GET_TTYPE(params->teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_REQUEST_CHANNEL, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_REQUEST_CHANNEL, ttype)) { IPA_USB_ERR("Illegal operation\n"); return -EPERM; } Loading Loading @@ -1347,7 +1374,7 @@ static int ipa3_usb_release_xdci_channel(u32 clnt_hdl, return -EINVAL; } if (!ipa3_usb_check_legal_op(IPA_USB_RELEASE_CHANNEL, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_RELEASE_CHANNEL, ttype)) { IPA_USB_ERR("Illegal operation.\n"); return -EPERM; } Loading Loading @@ -1511,81 +1538,79 @@ static int ipa3_usb_connect_dpl(void) return 0; } static int ipa3_usb_connect_teth_prot( struct ipa_usb_xdci_connect_params_internal *params, enum ipa3_usb_transport_type ttype) static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot) { int result; struct teth_bridge_connect_params teth_bridge_params; struct ipa3_usb_teth_prot_conn_params *teth_conn_params; enum ipa3_usb_transport_type ttype; IPA_USB_DBG("connecting protocol = %d\n", params->teth_prot); switch (params->teth_prot) { IPA_USB_DBG("connecting protocol = %s\n", ipa3_usb_teth_prot_to_string(teth_prot)); ttype = IPA3_USB_GET_TTYPE(teth_prot); teth_conn_params = &(ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params); switch (teth_prot) { case IPA_USB_RNDIS: if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; } ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].user_data; result = rndis_ipa_pipe_connect_notify( params->usb_to_ipa_clnt_hdl, params->ipa_to_usb_clnt_hdl, params->teth_prot_params.max_xfer_size_bytes_to_dev, params->teth_prot_params.max_packet_number_to_dev, params->teth_prot_params.max_xfer_size_bytes_to_host, teth_conn_params->usb_to_ipa_clnt_hdl, teth_conn_params->ipa_to_usb_clnt_hdl, teth_conn_params->params.max_xfer_size_bytes_to_dev, teth_conn_params->params.max_packet_number_to_dev, teth_conn_params->params.max_xfer_size_bytes_to_host, ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS]. teth_prot_params.rndis.private); if (result) { IPA_USB_ERR("failed to connect %s.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state = IPA_USB_TETH_PROT_CONNECTED; IPA_USB_DBG("%s is connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; case IPA_USB_ECM: if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; } ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].user_data; result = ecm_ipa_connect(params->usb_to_ipa_clnt_hdl, params->ipa_to_usb_clnt_hdl, result = ecm_ipa_connect(teth_conn_params->usb_to_ipa_clnt_hdl, teth_conn_params->ipa_to_usb_clnt_hdl, ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM]. teth_prot_params.ecm.private); if (result) { IPA_USB_ERR("failed to connect %s.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state = IPA_USB_TETH_PROT_CONNECTED; IPA_USB_DBG("%s is connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; case IPA_USB_RMNET: case IPA_USB_MBIM: if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state == if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; } result = ipa3_usb_init_teth_bridge(); Loading @@ -1593,14 +1618,14 @@ static int ipa3_usb_connect_teth_prot( return result; ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[params->teth_prot]. ipa3_usb_ctx->teth_prot_ctx[teth_prot]. user_data; teth_bridge_params.ipa_usb_pipe_hdl = params->ipa_to_usb_clnt_hdl; teth_conn_params->ipa_to_usb_clnt_hdl; teth_bridge_params.usb_ipa_pipe_hdl = params->usb_to_ipa_clnt_hdl; teth_conn_params->usb_to_ipa_clnt_hdl; teth_bridge_params.tethering_mode = (params->teth_prot == IPA_USB_RMNET) ? (teth_prot == IPA_USB_RMNET) ? (TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM); teth_bridge_params.client_type = IPA_CLIENT_USB_PROD; result = ipa3_usb_connect_teth_bridge(&teth_bridge_params); Loading @@ -1608,27 +1633,23 @@ static int ipa3_usb_connect_teth_prot( ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state = ipa3_usb_ctx->teth_prot_ctx[teth_prot].state = IPA_USB_TETH_PROT_CONNECTED; ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY); IPA_USB_DBG("%s (%s) is connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot), ipa3_usb_teth_bridge_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot), ipa3_usb_teth_bridge_prot_to_string(teth_prot)); break; case IPA_USB_DIAG: if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; } ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[params->teth_prot]. user_data; ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data; result = ipa3_usb_connect_dpl(); if (result) { IPA_USB_ERR("Failed connecting DPL result=%d\n", Loading @@ -1640,8 +1661,7 @@ static int ipa3_usb_connect_teth_prot( IPA_USB_TETH_PROT_CONNECTED; ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY); IPA_USB_DBG("%s is connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; default: IPA_USB_ERR("Invalid tethering protocol\n"); Loading Loading @@ -1775,11 +1795,19 @@ static int ipa3_usb_xdci_connect_internal( ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL : IPA_USB_TRANSPORT_TETH; if (!ipa3_usb_check_legal_op(IPA_USB_CONNECT, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); return -EPERM; } ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.ipa_to_usb_clnt_hdl = params->ipa_to_usb_clnt_hdl; if (!IPA3_USB_IS_TTYPE_DPL(ttype)) ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params. usb_to_ipa_clnt_hdl = params->usb_to_ipa_clnt_hdl; ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.params = params->teth_prot_params; /* Set EE xDCI specific scratch */ result = ipa3_set_usb_max_packet_size(params->max_pkt_size); if (result) { Loading Loading @@ -1816,7 +1844,7 @@ static int ipa3_usb_xdci_connect_internal( if (params->teth_prot != IPA_USB_DIAG) { /* Start UL channel */ result = ipa3_xdci_connect(params->usb_to_ipa_clnt_hdl, result = ipa3_xdci_start(params->usb_to_ipa_clnt_hdl, params->usb_to_ipa_xferrscidx, params->usb_to_ipa_xferrscidx_valid); if (result) { Loading @@ -1826,7 +1854,7 @@ static int ipa3_usb_xdci_connect_internal( } /* Start DL/DPL channel */ result = ipa3_xdci_connect(params->ipa_to_usb_clnt_hdl, result = ipa3_xdci_start(params->ipa_to_usb_clnt_hdl, params->ipa_to_usb_xferrscidx, params->ipa_to_usb_xferrscidx_valid); if (result) { Loading @@ -1835,7 +1863,7 @@ static int ipa3_usb_xdci_connect_internal( } /* Connect tethering protocol */ result = ipa3_usb_connect_teth_prot(params, ttype); result = ipa3_usb_connect_teth_prot(params->teth_prot); if (result) { IPA_USB_ERR("failed to connect teth protocol\n"); goto connect_teth_prot_fail; Loading Loading @@ -2164,6 +2192,70 @@ static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot) return 0; } /* Assumes lock already acquired */ static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { int result = 0; enum ipa3_usb_transport_type ttype; ttype = IPA3_USB_GET_TTYPE(teth_prot); IPA_USB_DBG_LOW("entry\n"); /* Reset DL channel */ result = ipa3_reset_gsi_channel(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset DL channel.\n"); return result; } /* Reset DL event ring */ result = ipa3_reset_gsi_event_ring(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset DL event ring.\n"); return result; } if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { /* Reset UL channel */ result = ipa3_reset_gsi_channel(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset UL channel.\n"); return result; } /* Reset UL event ring */ result = ipa3_reset_gsi_event_ring(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset UL event ring.\n"); return result; } } /* Change state to STOPPED */ if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype)) IPA_USB_ERR("failed to change state to stopped\n"); if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype); if (result) { IPA_USB_ERR("failed to release UL channel.\n"); return result; } } result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype); if (result) { IPA_USB_ERR("failed to release DL channel.\n"); return result; } IPA_USB_DBG_LOW("exit\n"); return 0; } int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { Loading @@ -2175,20 +2267,31 @@ int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); if (ipa3_usb_check_disconnect_prot(teth_prot)) { result = -EINVAL; goto bad_params; } ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_DISCONNECT, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_DISCONNECT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; } spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags); if (ipa3_usb_ctx->ttype_ctx[ttype].state == IPA_USB_SUSPENDED_NO_RWAKEUP) { spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl, teth_prot); mutex_unlock(&ipa3_usb_ctx->general_mutex); return result; } if (ipa3_usb_check_disconnect_prot(teth_prot)) { spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); result = -EINVAL; goto bad_params; } if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) { spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); /* Stop DL/DPL channel */ Loading Loading @@ -2227,53 +2330,10 @@ int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, } else spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); /* Reset DL channel */ result = ipa3_reset_gsi_channel(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset DL channel.\n"); goto bad_params; } /* Reset DL event ring */ result = ipa3_reset_gsi_event_ring(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset DL event ring.\n"); goto bad_params; } if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { /* Reset UL channel */ result = ipa3_reset_gsi_channel(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset UL channel.\n"); goto bad_params; } /* Reset UL event ring */ result = ipa3_reset_gsi_event_ring(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset UL event ring.\n"); goto bad_params; } } /* Change state to STOPPED */ if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype)) IPA_USB_ERR("failed to change state to stopped\n"); if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype); if (result) { IPA_USB_ERR("failed to release UL channel.\n"); goto bad_params; } } result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype); if (result) { IPA_USB_ERR("failed to release DL channel.\n"); result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl, teth_prot); if (result) goto bad_params; } /* Disconnect tethering protocol */ result = ipa3_usb_disconnect_teth_prot(teth_prot); Loading Loading @@ -2315,7 +2375,7 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot) ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_DEINIT_TETH_PROT, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_DEINIT_TETH_PROT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; Loading Loading @@ -2411,8 +2471,79 @@ bad_params: } EXPORT_SYMBOL(ipa_usb_deinit_teth_prot); int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, /* Assumes lock already acquired */ static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { int result = 0; enum ipa3_usb_transport_type ttype; ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND_NO_RWAKEUP, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto fail_exit; } IPA_USB_DBG("Start suspend with no remote wakeup sequence: %s\n", IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL channel":"Data Tethering channels"); if (ipa3_usb_check_disconnect_prot(teth_prot)) { result = -EINVAL; goto fail_exit; } /* Stop DL/DPL channel */ result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1); if (result) { IPA_USB_ERR("failed to disconnect DL/DPL channel.\n"); goto fail_exit; } if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { /* Stop UL channel */ result = ipa3_xdci_disconnect(ul_clnt_hdl, true, ipa3_usb_ctx->qmi_req_id); if (result) { IPA_USB_ERR("failed disconnect UL channel\n"); goto start_dl; } ipa3_usb_ctx->qmi_req_id++; } /* Disconnect tethering protocol */ result = ipa3_usb_disconnect_teth_prot(teth_prot); if (result) goto start_ul; result = ipa3_usb_release_prod(ttype); if (result) { IPA_USB_ERR("failed to release PROD.\n"); goto connect_teth; } /* Change ipa_usb state to SUSPENDED_NO_RWAKEUP */ if (!ipa3_usb_set_state(IPA_USB_SUSPENDED_NO_RWAKEUP, false, ttype)) IPA_USB_ERR("failed to change state to suspend no rwakeup\n"); IPA_USB_DBG_LOW("exit\n"); return 0; connect_teth: (void)ipa3_usb_connect_teth_prot(teth_prot); start_ul: if (!IPA3_USB_IS_TTYPE_DPL(ttype)) (void)ipa3_xdci_connect(ul_clnt_hdl); start_dl: (void)ipa3_xdci_connect(dl_clnt_hdl); fail_exit: return result; } int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot, bool with_remote_wakeup) { int result = 0; unsigned long flags; Loading @@ -2421,15 +2552,23 @@ int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) { IPA_USB_ERR("bad parameters.\n"); result = -EINVAL; goto bad_params; } if (!with_remote_wakeup) { result = ipa3_usb_suspend_no_remote_wakeup(ul_clnt_hdl, dl_clnt_hdl, teth_prot); mutex_unlock(&ipa3_usb_ctx->general_mutex); return result; } ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_SUSPEND, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; Loading Loading @@ -2538,6 +2677,72 @@ bad_params: } EXPORT_SYMBOL(ipa_usb_xdci_suspend); /* Assumes lock already acquired */ static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { int result = -EFAULT; enum ipa3_usb_transport_type ttype; ttype = IPA3_USB_GET_TTYPE(teth_prot); IPA_USB_DBG("Start resume with no remote wakeup sequence: %s\n", IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL channel":"Data Tethering channels"); /* Request USB_PROD */ result = ipa3_usb_request_prod(ttype); if (result) goto fail_exit; /* Connect tethering protocol */ result = ipa3_usb_connect_teth_prot(teth_prot); if (result) { IPA_USB_ERR("failed to connect teth protocol\n"); goto release_prod; } if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { /* Start UL channel */ result = ipa3_xdci_connect(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to start UL channel.\n"); goto disconn_teth; } } /* Start DL/DPL channel */ result = ipa3_xdci_connect(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to start DL/DPL channel.\n"); goto stop_ul; } /* Change state to CONNECTED */ if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) { IPA_USB_ERR("failed to change state to connected\n"); result = -EFAULT; goto stop_dl; } return 0; stop_dl: (void)ipa3_xdci_disconnect(dl_clnt_hdl, false, -1); stop_ul: if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { (void)ipa3_xdci_disconnect(ul_clnt_hdl, true, ipa3_usb_ctx->qmi_req_id); ipa3_usb_ctx->qmi_req_id++; } disconn_teth: (void)ipa3_usb_disconnect_teth_prot(teth_prot); release_prod: (void)ipa3_usb_release_prod(ttype); fail_exit: return result; } int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { Loading @@ -2557,19 +2762,25 @@ int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_RESUME, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_RESUME, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; } IPA_USB_DBG_LOW("Start resume sequence: %s\n", IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL channel" : "Data Tethering channels"); spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags); prev_state = ipa3_usb_ctx->ttype_ctx[ttype].state; spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); if (prev_state == IPA_USB_SUSPENDED_NO_RWAKEUP) { result = ipa3_usb_resume_no_remote_wakeup(ul_clnt_hdl, dl_clnt_hdl, teth_prot); mutex_unlock(&ipa3_usb_ctx->general_mutex); return result; } IPA_USB_DBG("Start resume sequence: %s\n", IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL channel" : "Data Tethering channels"); /* Change state to RESUME_IN_PROGRESS */ if (!ipa3_usb_set_state(IPA_USB_RESUME_IN_PROGRESS, false, ttype)) { Loading drivers/platform/msm/ipa/ipa_v3/ipa_client.c +42 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes drivers/platform/msm/ipa/ipa_v3/ipa_i.h +3 −1 Original line number Diff line number Diff line Loading @@ -1462,7 +1462,9 @@ int ipa3_reset_gsi_event_ring(u32 clnt_hdl); int ipa3_set_usb_max_packet_size( enum ipa_usb_max_usb_packet_size usb_max_packet_size); int ipa3_xdci_connect(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid); int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid); int ipa3_xdci_connect(u32 clnt_hdl); int ipa3_xdci_disconnect(u32 clnt_hdl, bool should_force_clear, u32 qmi_req_id); Loading drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +1 −1 Original line number Diff line number Diff line Loading @@ -5000,7 +5000,7 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl) goto end_sequence; IPADBG("Inject a DMA_TASK with 1B packet to IPA and retry\n"); /* Send a 1B packet DMA_RASK to IPA and try again*/ /* Send a 1B packet DMA_TASK to IPA and try again */ res = ipa3_inject_dma_task_for_gsi(); if (res) { IPAERR("Failed to inject DMA TASk for GSI\n"); Loading drivers/usb/gadget/function/f_gsi.c +2 −1 Original line number Diff line number Diff line Loading @@ -940,7 +940,8 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) log_event_dbg("%s: Calling xdci_suspend", __func__); ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle, gsi->d_port.in_channel_handle, gsi->prot_id); gsi->d_port.in_channel_handle, gsi->prot_id, true); if (!ret) { d_port->sm_state = STATE_SUSPENDED; Loading Loading
drivers/platform/msm/ipa/ipa_clients/ipa_usb.c +355 −144 Original line number Diff line number Diff line Loading @@ -127,6 +127,7 @@ enum ipa3_usb_state { IPA_USB_SUSPEND_REQUESTED, IPA_USB_SUSPEND_IN_PROGRESS, IPA_USB_SUSPENDED, IPA_USB_SUSPENDED_NO_RWAKEUP, IPA_USB_RESUME_IN_PROGRESS }; Loading @@ -152,6 +153,12 @@ struct finish_suspend_work_context { u32 ul_clnt_hdl; }; struct ipa3_usb_teth_prot_conn_params { u32 usb_to_ipa_clnt_hdl; u32 ipa_to_usb_clnt_hdl; struct ipa_usb_teth_prot_params params; }; /** * Transport type - could be either data tethering or DPL * Each transport has it's own RM resources and statuses Loading @@ -163,6 +170,7 @@ struct ipa3_usb_transport_type_ctx { enum ipa3_usb_state state; struct finish_suspend_work_context finish_suspend_work; struct ipa_usb_xdci_chan_params ch_params; struct ipa3_usb_teth_prot_conn_params teth_conn_params; }; struct ipa3_usb_smmu_reg_map { Loading @@ -189,14 +197,15 @@ struct ipa3_usb_context { }; enum ipa3_usb_op { IPA_USB_INIT_TETH_PROT, IPA_USB_REQUEST_CHANNEL, IPA_USB_CONNECT, IPA_USB_DISCONNECT, IPA_USB_RELEASE_CHANNEL, IPA_USB_DEINIT_TETH_PROT, IPA_USB_SUSPEND, IPA_USB_RESUME IPA_USB_OP_INIT_TETH_PROT, IPA_USB_OP_REQUEST_CHANNEL, IPA_USB_OP_CONNECT, IPA_USB_OP_DISCONNECT, IPA_USB_OP_RELEASE_CHANNEL, IPA_USB_OP_DEINIT_TETH_PROT, IPA_USB_OP_SUSPEND, IPA_USB_OP_SUSPEND_NO_RWAKEUP, IPA_USB_OP_RESUME }; struct ipa3_usb_status_dbg_info { Loading Loading @@ -228,22 +237,24 @@ struct ipa3_usb_context *ipa3_usb_ctx; static char *ipa3_usb_op_to_string(enum ipa3_usb_op op) { switch (op) { case IPA_USB_INIT_TETH_PROT: return "IPA_USB_INIT_TETH_PROT"; case IPA_USB_REQUEST_CHANNEL: return "IPA_USB_REQUEST_CHANNEL"; case IPA_USB_CONNECT: return "IPA_USB_CONNECT"; case IPA_USB_DISCONNECT: return "IPA_USB_DISCONNECT"; case IPA_USB_RELEASE_CHANNEL: return "IPA_USB_RELEASE_CHANNEL"; case IPA_USB_DEINIT_TETH_PROT: return "IPA_USB_DEINIT_TETH_PROT"; case IPA_USB_SUSPEND: return "IPA_USB_SUSPEND"; case IPA_USB_RESUME: return "IPA_USB_RESUME"; case IPA_USB_OP_INIT_TETH_PROT: return "IPA_USB_OP_INIT_TETH_PROT"; case IPA_USB_OP_REQUEST_CHANNEL: return "IPA_USB_OP_REQUEST_CHANNEL"; case IPA_USB_OP_CONNECT: return "IPA_USB_OP_CONNECT"; case IPA_USB_OP_DISCONNECT: return "IPA_USB_OP_DISCONNECT"; case IPA_USB_OP_RELEASE_CHANNEL: return "IPA_USB_OP_RELEASE_CHANNEL"; case IPA_USB_OP_DEINIT_TETH_PROT: return "IPA_USB_OP_DEINIT_TETH_PROT"; case IPA_USB_OP_SUSPEND: return "IPA_USB_OP_SUSPEND"; case IPA_USB_OP_SUSPEND_NO_RWAKEUP: return "IPA_USB_OP_SUSPEND_NO_RWAKEUP"; case IPA_USB_OP_RESUME: return "IPA_USB_OP_RESUME"; } return "UNSUPPORTED"; Loading @@ -266,6 +277,8 @@ static char *ipa3_usb_state_to_string(enum ipa3_usb_state state) return "IPA_USB_SUSPEND_IN_PROGRESS"; case IPA_USB_SUSPENDED: return "IPA_USB_SUSPENDED"; case IPA_USB_SUSPENDED_NO_RWAKEUP: return "IPA_USB_SUSPENDED_NO_RWAKEUP"; case IPA_USB_RESUME_IN_PROGRESS: return "IPA_USB_RESUME_IN_PROGRESS"; } Loading Loading @@ -312,6 +325,7 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit, if (state == IPA_USB_INITIALIZED || state == IPA_USB_STOPPED || state == IPA_USB_RESUME_IN_PROGRESS || state == IPA_USB_SUSPENDED_NO_RWAKEUP || /* * In case of failure during suspend request * handling, state is reverted to connected. Loading @@ -327,7 +341,8 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit, case IPA_USB_STOPPED: if (state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_CONNECTED || state == IPA_USB_SUSPENDED) state == IPA_USB_SUSPENDED || state == IPA_USB_SUSPENDED_NO_RWAKEUP) state_legal = true; break; case IPA_USB_SUSPEND_REQUESTED: Loading @@ -354,6 +369,10 @@ static bool ipa3_usb_set_state(enum ipa3_usb_state new_state, bool err_permit, (err_permit && state == IPA_USB_RESUME_IN_PROGRESS)) state_legal = true; break; case IPA_USB_SUSPENDED_NO_RWAKEUP: if (state == IPA_USB_CONNECTED) state_legal = true; break; case IPA_USB_RESUME_IN_PROGRESS: if (state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_SUSPENDED) Loading Loading @@ -418,32 +437,33 @@ static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op, spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags); state = ipa3_usb_ctx->ttype_ctx[ttype].state; switch (op) { case IPA_USB_INIT_TETH_PROT: case IPA_USB_OP_INIT_TETH_PROT: if (state == IPA_USB_INVALID || (!is_dpl && state == IPA_USB_INITIALIZED)) is_legal = true; break; case IPA_USB_REQUEST_CHANNEL: case IPA_USB_OP_REQUEST_CHANNEL: if (state == IPA_USB_INITIALIZED) is_legal = true; break; case IPA_USB_CONNECT: case IPA_USB_OP_CONNECT: if (state == IPA_USB_INITIALIZED || state == IPA_USB_STOPPED) is_legal = true; break; case IPA_USB_DISCONNECT: case IPA_USB_OP_DISCONNECT: if (state == IPA_USB_CONNECTED || state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_SUSPENDED) state == IPA_USB_SUSPENDED || state == IPA_USB_SUSPENDED_NO_RWAKEUP) is_legal = true; break; case IPA_USB_RELEASE_CHANNEL: case IPA_USB_OP_RELEASE_CHANNEL: /* when releasing 1st channel state will be changed already */ if (state == IPA_USB_STOPPED || (!is_dpl && state == IPA_USB_INITIALIZED)) is_legal = true; break; case IPA_USB_DEINIT_TETH_PROT: case IPA_USB_OP_DEINIT_TETH_PROT: /* * For data tethering we should allow deinit an inited protocol * always. E.g. rmnet is inited and rndis is connected. Loading @@ -453,13 +473,18 @@ static bool ipa3_usb_check_legal_op(enum ipa3_usb_op op, if (!is_dpl || state == IPA_USB_INITIALIZED) is_legal = true; break; case IPA_USB_SUSPEND: case IPA_USB_OP_SUSPEND: if (state == IPA_USB_CONNECTED) is_legal = true; break; case IPA_USB_RESUME: case IPA_USB_OP_SUSPEND_NO_RWAKEUP: if (state == IPA_USB_CONNECTED) is_legal = true; break; case IPA_USB_OP_RESUME: if (state == IPA_USB_SUSPENDED || state == IPA_USB_SUSPEND_IN_PROGRESS) state == IPA_USB_SUSPEND_IN_PROGRESS || state == IPA_USB_SUSPENDED_NO_RWAKEUP) is_legal = true; break; default: Loading Loading @@ -638,6 +663,7 @@ static int ipa3_usb_cons_request_resource_cb_do( ipa3_usb_ctx->ttype_ctx[ttype].state)); switch (ipa3_usb_ctx->ttype_ctx[ttype].state) { case IPA_USB_CONNECTED: case IPA_USB_SUSPENDED_NO_RWAKEUP: rm_ctx->cons_state = IPA_USB_CONS_GRANTED; result = 0; break; Loading Loading @@ -717,6 +743,7 @@ static int ipa3_usb_cons_release_resource_cb_do( break; case IPA_USB_STOPPED: case IPA_USB_RESUME_IN_PROGRESS: case IPA_USB_SUSPENDED_NO_RWAKEUP: if (rm_ctx->cons_requested) rm_ctx->cons_requested = false; break; Loading Loading @@ -886,7 +913,7 @@ int ipa_usb_init_teth_prot(enum ipa_usb_teth_prot teth_prot, ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_INIT_TETH_PROT, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_INIT_TETH_PROT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; Loading Loading @@ -1204,7 +1231,7 @@ static int ipa3_usb_request_xdci_channel( ttype = IPA3_USB_GET_TTYPE(params->teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_REQUEST_CHANNEL, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_REQUEST_CHANNEL, ttype)) { IPA_USB_ERR("Illegal operation\n"); return -EPERM; } Loading Loading @@ -1347,7 +1374,7 @@ static int ipa3_usb_release_xdci_channel(u32 clnt_hdl, return -EINVAL; } if (!ipa3_usb_check_legal_op(IPA_USB_RELEASE_CHANNEL, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_RELEASE_CHANNEL, ttype)) { IPA_USB_ERR("Illegal operation.\n"); return -EPERM; } Loading Loading @@ -1511,81 +1538,79 @@ static int ipa3_usb_connect_dpl(void) return 0; } static int ipa3_usb_connect_teth_prot( struct ipa_usb_xdci_connect_params_internal *params, enum ipa3_usb_transport_type ttype) static int ipa3_usb_connect_teth_prot(enum ipa_usb_teth_prot teth_prot) { int result; struct teth_bridge_connect_params teth_bridge_params; struct ipa3_usb_teth_prot_conn_params *teth_conn_params; enum ipa3_usb_transport_type ttype; IPA_USB_DBG("connecting protocol = %d\n", params->teth_prot); switch (params->teth_prot) { IPA_USB_DBG("connecting protocol = %s\n", ipa3_usb_teth_prot_to_string(teth_prot)); ttype = IPA3_USB_GET_TTYPE(teth_prot); teth_conn_params = &(ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params); switch (teth_prot) { case IPA_USB_RNDIS: if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; } ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].user_data; result = rndis_ipa_pipe_connect_notify( params->usb_to_ipa_clnt_hdl, params->ipa_to_usb_clnt_hdl, params->teth_prot_params.max_xfer_size_bytes_to_dev, params->teth_prot_params.max_packet_number_to_dev, params->teth_prot_params.max_xfer_size_bytes_to_host, teth_conn_params->usb_to_ipa_clnt_hdl, teth_conn_params->ipa_to_usb_clnt_hdl, teth_conn_params->params.max_xfer_size_bytes_to_dev, teth_conn_params->params.max_packet_number_to_dev, teth_conn_params->params.max_xfer_size_bytes_to_host, ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS]. teth_prot_params.rndis.private); if (result) { IPA_USB_ERR("failed to connect %s.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } ipa3_usb_ctx->teth_prot_ctx[IPA_USB_RNDIS].state = IPA_USB_TETH_PROT_CONNECTED; IPA_USB_DBG("%s is connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; case IPA_USB_ECM: if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; } ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].user_data; result = ecm_ipa_connect(params->usb_to_ipa_clnt_hdl, params->ipa_to_usb_clnt_hdl, result = ecm_ipa_connect(teth_conn_params->usb_to_ipa_clnt_hdl, teth_conn_params->ipa_to_usb_clnt_hdl, ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM]. teth_prot_params.ecm.private); if (result) { IPA_USB_ERR("failed to connect %s.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } ipa3_usb_ctx->teth_prot_ctx[IPA_USB_ECM].state = IPA_USB_TETH_PROT_CONNECTED; IPA_USB_DBG("%s is connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; case IPA_USB_RMNET: case IPA_USB_MBIM: if (ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state == if (ipa3_usb_ctx->teth_prot_ctx[teth_prot].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; } result = ipa3_usb_init_teth_bridge(); Loading @@ -1593,14 +1618,14 @@ static int ipa3_usb_connect_teth_prot( return result; ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[params->teth_prot]. ipa3_usb_ctx->teth_prot_ctx[teth_prot]. user_data; teth_bridge_params.ipa_usb_pipe_hdl = params->ipa_to_usb_clnt_hdl; teth_conn_params->ipa_to_usb_clnt_hdl; teth_bridge_params.usb_ipa_pipe_hdl = params->usb_to_ipa_clnt_hdl; teth_conn_params->usb_to_ipa_clnt_hdl; teth_bridge_params.tethering_mode = (params->teth_prot == IPA_USB_RMNET) ? (teth_prot == IPA_USB_RMNET) ? (TETH_TETHERING_MODE_RMNET):(TETH_TETHERING_MODE_MBIM); teth_bridge_params.client_type = IPA_CLIENT_USB_PROD; result = ipa3_usb_connect_teth_bridge(&teth_bridge_params); Loading @@ -1608,27 +1633,23 @@ static int ipa3_usb_connect_teth_prot( ipa3_usb_ctx->ttype_ctx[ttype].user_data = NULL; return result; } ipa3_usb_ctx->teth_prot_ctx[params->teth_prot].state = ipa3_usb_ctx->teth_prot_ctx[teth_prot].state = IPA_USB_TETH_PROT_CONNECTED; ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY); IPA_USB_DBG("%s (%s) is connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot), ipa3_usb_teth_bridge_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot), ipa3_usb_teth_bridge_prot_to_string(teth_prot)); break; case IPA_USB_DIAG: if (ipa3_usb_ctx->teth_prot_ctx[IPA_USB_DIAG].state == IPA_USB_TETH_PROT_CONNECTED) { IPA_USB_DBG("%s is already connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; } ipa3_usb_ctx->ttype_ctx[ttype].user_data = ipa3_usb_ctx->teth_prot_ctx[params->teth_prot]. user_data; ipa3_usb_ctx->teth_prot_ctx[teth_prot].user_data; result = ipa3_usb_connect_dpl(); if (result) { IPA_USB_ERR("Failed connecting DPL result=%d\n", Loading @@ -1640,8 +1661,7 @@ static int ipa3_usb_connect_teth_prot( IPA_USB_TETH_PROT_CONNECTED; ipa3_usb_notify_do(ttype, IPA_USB_DEVICE_READY); IPA_USB_DBG("%s is connected.\n", ipa3_usb_teth_prot_to_string( params->teth_prot)); ipa3_usb_teth_prot_to_string(teth_prot)); break; default: IPA_USB_ERR("Invalid tethering protocol\n"); Loading Loading @@ -1775,11 +1795,19 @@ static int ipa3_usb_xdci_connect_internal( ttype = (params->teth_prot == IPA_USB_DIAG) ? IPA_USB_TRANSPORT_DPL : IPA_USB_TRANSPORT_TETH; if (!ipa3_usb_check_legal_op(IPA_USB_CONNECT, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_CONNECT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); return -EPERM; } ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.ipa_to_usb_clnt_hdl = params->ipa_to_usb_clnt_hdl; if (!IPA3_USB_IS_TTYPE_DPL(ttype)) ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params. usb_to_ipa_clnt_hdl = params->usb_to_ipa_clnt_hdl; ipa3_usb_ctx->ttype_ctx[ttype].teth_conn_params.params = params->teth_prot_params; /* Set EE xDCI specific scratch */ result = ipa3_set_usb_max_packet_size(params->max_pkt_size); if (result) { Loading Loading @@ -1816,7 +1844,7 @@ static int ipa3_usb_xdci_connect_internal( if (params->teth_prot != IPA_USB_DIAG) { /* Start UL channel */ result = ipa3_xdci_connect(params->usb_to_ipa_clnt_hdl, result = ipa3_xdci_start(params->usb_to_ipa_clnt_hdl, params->usb_to_ipa_xferrscidx, params->usb_to_ipa_xferrscidx_valid); if (result) { Loading @@ -1826,7 +1854,7 @@ static int ipa3_usb_xdci_connect_internal( } /* Start DL/DPL channel */ result = ipa3_xdci_connect(params->ipa_to_usb_clnt_hdl, result = ipa3_xdci_start(params->ipa_to_usb_clnt_hdl, params->ipa_to_usb_xferrscidx, params->ipa_to_usb_xferrscidx_valid); if (result) { Loading @@ -1835,7 +1863,7 @@ static int ipa3_usb_xdci_connect_internal( } /* Connect tethering protocol */ result = ipa3_usb_connect_teth_prot(params, ttype); result = ipa3_usb_connect_teth_prot(params->teth_prot); if (result) { IPA_USB_ERR("failed to connect teth protocol\n"); goto connect_teth_prot_fail; Loading Loading @@ -2164,6 +2192,70 @@ static int ipa3_usb_check_disconnect_prot(enum ipa_usb_teth_prot teth_prot) return 0; } /* Assumes lock already acquired */ static int ipa_usb_xdci_dismiss_channels(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { int result = 0; enum ipa3_usb_transport_type ttype; ttype = IPA3_USB_GET_TTYPE(teth_prot); IPA_USB_DBG_LOW("entry\n"); /* Reset DL channel */ result = ipa3_reset_gsi_channel(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset DL channel.\n"); return result; } /* Reset DL event ring */ result = ipa3_reset_gsi_event_ring(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset DL event ring.\n"); return result; } if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { /* Reset UL channel */ result = ipa3_reset_gsi_channel(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset UL channel.\n"); return result; } /* Reset UL event ring */ result = ipa3_reset_gsi_event_ring(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset UL event ring.\n"); return result; } } /* Change state to STOPPED */ if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype)) IPA_USB_ERR("failed to change state to stopped\n"); if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype); if (result) { IPA_USB_ERR("failed to release UL channel.\n"); return result; } } result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype); if (result) { IPA_USB_ERR("failed to release DL channel.\n"); return result; } IPA_USB_DBG_LOW("exit\n"); return 0; } int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { Loading @@ -2175,20 +2267,31 @@ int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); if (ipa3_usb_check_disconnect_prot(teth_prot)) { result = -EINVAL; goto bad_params; } ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_DISCONNECT, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_DISCONNECT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; } spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags); if (ipa3_usb_ctx->ttype_ctx[ttype].state == IPA_USB_SUSPENDED_NO_RWAKEUP) { spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl, teth_prot); mutex_unlock(&ipa3_usb_ctx->general_mutex); return result; } if (ipa3_usb_check_disconnect_prot(teth_prot)) { spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); result = -EINVAL; goto bad_params; } if (ipa3_usb_ctx->ttype_ctx[ttype].state != IPA_USB_SUSPENDED) { spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); /* Stop DL/DPL channel */ Loading Loading @@ -2227,53 +2330,10 @@ int ipa_usb_xdci_disconnect(u32 ul_clnt_hdl, u32 dl_clnt_hdl, } else spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); /* Reset DL channel */ result = ipa3_reset_gsi_channel(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset DL channel.\n"); goto bad_params; } /* Reset DL event ring */ result = ipa3_reset_gsi_event_ring(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset DL event ring.\n"); goto bad_params; } if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { /* Reset UL channel */ result = ipa3_reset_gsi_channel(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset UL channel.\n"); goto bad_params; } /* Reset UL event ring */ result = ipa3_reset_gsi_event_ring(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to reset UL event ring.\n"); goto bad_params; } } /* Change state to STOPPED */ if (!ipa3_usb_set_state(IPA_USB_STOPPED, false, ttype)) IPA_USB_ERR("failed to change state to stopped\n"); if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { result = ipa3_usb_release_xdci_channel(ul_clnt_hdl, ttype); if (result) { IPA_USB_ERR("failed to release UL channel.\n"); goto bad_params; } } result = ipa3_usb_release_xdci_channel(dl_clnt_hdl, ttype); if (result) { IPA_USB_ERR("failed to release DL channel.\n"); result = ipa_usb_xdci_dismiss_channels(ul_clnt_hdl, dl_clnt_hdl, teth_prot); if (result) goto bad_params; } /* Disconnect tethering protocol */ result = ipa3_usb_disconnect_teth_prot(teth_prot); Loading Loading @@ -2315,7 +2375,7 @@ int ipa_usb_deinit_teth_prot(enum ipa_usb_teth_prot teth_prot) ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_DEINIT_TETH_PROT, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_DEINIT_TETH_PROT, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; Loading Loading @@ -2411,8 +2471,79 @@ bad_params: } EXPORT_SYMBOL(ipa_usb_deinit_teth_prot); int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, /* Assumes lock already acquired */ static int ipa3_usb_suspend_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { int result = 0; enum ipa3_usb_transport_type ttype; ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND_NO_RWAKEUP, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto fail_exit; } IPA_USB_DBG("Start suspend with no remote wakeup sequence: %s\n", IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL channel":"Data Tethering channels"); if (ipa3_usb_check_disconnect_prot(teth_prot)) { result = -EINVAL; goto fail_exit; } /* Stop DL/DPL channel */ result = ipa3_xdci_disconnect(dl_clnt_hdl, false, -1); if (result) { IPA_USB_ERR("failed to disconnect DL/DPL channel.\n"); goto fail_exit; } if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { /* Stop UL channel */ result = ipa3_xdci_disconnect(ul_clnt_hdl, true, ipa3_usb_ctx->qmi_req_id); if (result) { IPA_USB_ERR("failed disconnect UL channel\n"); goto start_dl; } ipa3_usb_ctx->qmi_req_id++; } /* Disconnect tethering protocol */ result = ipa3_usb_disconnect_teth_prot(teth_prot); if (result) goto start_ul; result = ipa3_usb_release_prod(ttype); if (result) { IPA_USB_ERR("failed to release PROD.\n"); goto connect_teth; } /* Change ipa_usb state to SUSPENDED_NO_RWAKEUP */ if (!ipa3_usb_set_state(IPA_USB_SUSPENDED_NO_RWAKEUP, false, ttype)) IPA_USB_ERR("failed to change state to suspend no rwakeup\n"); IPA_USB_DBG_LOW("exit\n"); return 0; connect_teth: (void)ipa3_usb_connect_teth_prot(teth_prot); start_ul: if (!IPA3_USB_IS_TTYPE_DPL(ttype)) (void)ipa3_xdci_connect(ul_clnt_hdl); start_dl: (void)ipa3_xdci_connect(dl_clnt_hdl); fail_exit: return result; } int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot, bool with_remote_wakeup) { int result = 0; unsigned long flags; Loading @@ -2421,15 +2552,23 @@ int ipa_usb_xdci_suspend(u32 ul_clnt_hdl, u32 dl_clnt_hdl, mutex_lock(&ipa3_usb_ctx->general_mutex); IPA_USB_DBG_LOW("entry\n"); if (teth_prot > IPA_USB_MAX_TETH_PROT_SIZE) { IPA_USB_ERR("bad parameters.\n"); result = -EINVAL; goto bad_params; } if (!with_remote_wakeup) { result = ipa3_usb_suspend_no_remote_wakeup(ul_clnt_hdl, dl_clnt_hdl, teth_prot); mutex_unlock(&ipa3_usb_ctx->general_mutex); return result; } ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_SUSPEND, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_SUSPEND, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; Loading Loading @@ -2538,6 +2677,72 @@ bad_params: } EXPORT_SYMBOL(ipa_usb_xdci_suspend); /* Assumes lock already acquired */ static int ipa3_usb_resume_no_remote_wakeup(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { int result = -EFAULT; enum ipa3_usb_transport_type ttype; ttype = IPA3_USB_GET_TTYPE(teth_prot); IPA_USB_DBG("Start resume with no remote wakeup sequence: %s\n", IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL channel":"Data Tethering channels"); /* Request USB_PROD */ result = ipa3_usb_request_prod(ttype); if (result) goto fail_exit; /* Connect tethering protocol */ result = ipa3_usb_connect_teth_prot(teth_prot); if (result) { IPA_USB_ERR("failed to connect teth protocol\n"); goto release_prod; } if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { /* Start UL channel */ result = ipa3_xdci_connect(ul_clnt_hdl); if (result) { IPA_USB_ERR("failed to start UL channel.\n"); goto disconn_teth; } } /* Start DL/DPL channel */ result = ipa3_xdci_connect(dl_clnt_hdl); if (result) { IPA_USB_ERR("failed to start DL/DPL channel.\n"); goto stop_ul; } /* Change state to CONNECTED */ if (!ipa3_usb_set_state(IPA_USB_CONNECTED, false, ttype)) { IPA_USB_ERR("failed to change state to connected\n"); result = -EFAULT; goto stop_dl; } return 0; stop_dl: (void)ipa3_xdci_disconnect(dl_clnt_hdl, false, -1); stop_ul: if (!IPA3_USB_IS_TTYPE_DPL(ttype)) { (void)ipa3_xdci_disconnect(ul_clnt_hdl, true, ipa3_usb_ctx->qmi_req_id); ipa3_usb_ctx->qmi_req_id++; } disconn_teth: (void)ipa3_usb_disconnect_teth_prot(teth_prot); release_prod: (void)ipa3_usb_release_prod(ttype); fail_exit: return result; } int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, enum ipa_usb_teth_prot teth_prot) { Loading @@ -2557,19 +2762,25 @@ int ipa_usb_xdci_resume(u32 ul_clnt_hdl, u32 dl_clnt_hdl, ttype = IPA3_USB_GET_TTYPE(teth_prot); if (!ipa3_usb_check_legal_op(IPA_USB_RESUME, ttype)) { if (!ipa3_usb_check_legal_op(IPA_USB_OP_RESUME, ttype)) { IPA_USB_ERR("Illegal operation.\n"); result = -EPERM; goto bad_params; } IPA_USB_DBG_LOW("Start resume sequence: %s\n", IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL channel" : "Data Tethering channels"); spin_lock_irqsave(&ipa3_usb_ctx->state_lock, flags); prev_state = ipa3_usb_ctx->ttype_ctx[ttype].state; spin_unlock_irqrestore(&ipa3_usb_ctx->state_lock, flags); if (prev_state == IPA_USB_SUSPENDED_NO_RWAKEUP) { result = ipa3_usb_resume_no_remote_wakeup(ul_clnt_hdl, dl_clnt_hdl, teth_prot); mutex_unlock(&ipa3_usb_ctx->general_mutex); return result; } IPA_USB_DBG("Start resume sequence: %s\n", IPA3_USB_IS_TTYPE_DPL(ttype) ? "DPL channel" : "Data Tethering channels"); /* Change state to RESUME_IN_PROGRESS */ if (!ipa3_usb_set_state(IPA_USB_RESUME_IN_PROGRESS, false, ttype)) { Loading
drivers/platform/msm/ipa/ipa_v3/ipa_client.c +42 −3 File changed.Preview size limit exceeded, changes collapsed. Show changes
drivers/platform/msm/ipa/ipa_v3/ipa_i.h +3 −1 Original line number Diff line number Diff line Loading @@ -1462,7 +1462,9 @@ int ipa3_reset_gsi_event_ring(u32 clnt_hdl); int ipa3_set_usb_max_packet_size( enum ipa_usb_max_usb_packet_size usb_max_packet_size); int ipa3_xdci_connect(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid); int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid); int ipa3_xdci_connect(u32 clnt_hdl); int ipa3_xdci_disconnect(u32 clnt_hdl, bool should_force_clear, u32 qmi_req_id); Loading
drivers/platform/msm/ipa/ipa_v3/ipa_utils.c +1 −1 Original line number Diff line number Diff line Loading @@ -5000,7 +5000,7 @@ int ipa3_stop_gsi_channel(u32 clnt_hdl) goto end_sequence; IPADBG("Inject a DMA_TASK with 1B packet to IPA and retry\n"); /* Send a 1B packet DMA_RASK to IPA and try again*/ /* Send a 1B packet DMA_TASK to IPA and try again */ res = ipa3_inject_dma_task_for_gsi(); if (res) { IPAERR("Failed to inject DMA TASk for GSI\n"); Loading
drivers/usb/gadget/function/f_gsi.c +2 −1 Original line number Diff line number Diff line Loading @@ -940,7 +940,8 @@ static int ipa_suspend_work_handler(struct gsi_data_port *d_port) log_event_dbg("%s: Calling xdci_suspend", __func__); ret = ipa_usb_xdci_suspend(gsi->d_port.out_channel_handle, gsi->d_port.in_channel_handle, gsi->prot_id); gsi->d_port.in_channel_handle, gsi->prot_id, true); if (!ret) { d_port->sm_state = STATE_SUSPENDED; Loading