summaryrefslogtreecommitdiff
path: root/drivers/platform
diff options
context:
space:
mode:
authorLinux Build Service Account <lnxbuild@localhost>2016-10-31 06:59:10 -0700
committerGerrit - the friendly Code Review server <code-review@localhost>2016-10-31 06:59:10 -0700
commit9178072f99e5921391257cc5846f711c9cf526dc (patch)
tree53e3eb46fa71d9a09bb30889095017f2814fdc44 /drivers/platform
parentdeca532c2980b3514c30dc8bc3f00011ce2ed229 (diff)
parente1cf6bb611cb9788fc1095a86926b1e1bf70048a (diff)
Merge "msm: ipa3: Support IPA-USB suspend sequence without remote wake-up"
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/msm/ipa/ipa_clients/ipa_usb.c499
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_client.c45
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_i.h4
-rw-r--r--drivers/platform/msm/ipa/ipa_v3/ipa_utils.c2
4 files changed, 401 insertions, 149 deletions
diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
index d18308344431..293371b88ab9 100644
--- a/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
+++ b/drivers/platform/msm/ipa/ipa_clients/ipa_usb.c
@@ -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
};
@@ -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
@@ -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 {
@@ -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 {
@@ -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";
@@ -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";
}
@@ -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.
@@ -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:
@@ -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)
@@ -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.
@@ -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:
@@ -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;
@@ -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;
@@ -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;
@@ -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;
}
@@ -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;
}
@@ -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();
@@ -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);
@@ -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",
@@ -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");
@@ -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) {
@@ -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) {
@@ -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) {
@@ -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;
@@ -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)
{
@@ -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 */
@@ -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);
@@ -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;
@@ -2411,25 +2471,104 @@ 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;
enum ipa3_usb_cons_state curr_cons_state;
enum ipa3_usb_transport_type ttype;
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;
@@ -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)
{
@@ -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)) {
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
index 8326c3fdd9d1..d176552a3533 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c
@@ -61,7 +61,7 @@ int ipa3_enable_data_path(u32 clnt_hdl)
!ipa3_should_pipe_be_suspended(ep->client))) {
memset(&ep_cfg_ctrl, 0 , sizeof(ep_cfg_ctrl));
ep_cfg_ctrl.ipa_ep_suspend = false;
- ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+ res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
}
/* Assign the resource group for pipe */
@@ -101,7 +101,7 @@ int ipa3_disable_data_path(u32 clnt_hdl)
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;
- ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
+ res = ipa3_cfg_ep_ctrl(clnt_hdl, &ep_cfg_ctrl);
}
udelay(IPA_PKT_FLUSH_TO_US);
@@ -1311,7 +1311,46 @@ int ipa3_set_usb_max_packet_size(
return 0;
}
-int ipa3_xdci_connect(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid)
+int ipa3_xdci_connect(u32 clnt_hdl)
+{
+ int result;
+ struct ipa3_ep_context *ep;
+
+ IPADBG("entry\n");
+
+ if (clnt_hdl >= ipa3_ctx->ipa_num_pipes ||
+ ipa3_ctx->ep[clnt_hdl].valid == 0) {
+ IPAERR("Bad parameter.\n");
+ return -EINVAL;
+ }
+
+ ep = &ipa3_ctx->ep[clnt_hdl];
+ IPA_ACTIVE_CLIENTS_INC_EP(ipa3_get_client_mapping(clnt_hdl));
+
+ result = ipa3_start_gsi_channel(clnt_hdl);
+ if (result) {
+ IPAERR("failed to start gsi channel clnt_hdl=%u\n", clnt_hdl);
+ goto exit;
+ }
+
+ result = ipa3_enable_data_path(clnt_hdl);
+ if (result) {
+ IPAERR("enable data path failed res=%d clnt_hdl=%d.\n", result,
+ clnt_hdl);
+ goto stop_ch;
+ }
+
+ IPADBG("exit\n");
+ goto exit;
+
+stop_ch:
+ (void)ipa3_stop_gsi_channel(clnt_hdl);
+exit:
+ IPA_ACTIVE_CLIENTS_DEC_EP(ipa3_get_client_mapping(clnt_hdl));
+ return result;
+}
+
+int ipa3_xdci_start(u32 clnt_hdl, u8 xferrscidx, bool xferrscidx_valid)
{
struct ipa3_ep_context *ep;
int result = -EFAULT;
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
index 33be22f98b9d..96cd550d7ef6 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h
@@ -1482,7 +1482,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);
diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
index c0a6e8b00d71..4ea68ae1e95c 100644
--- a/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
+++ b/drivers/platform/msm/ipa/ipa_v3/ipa_utils.c
@@ -3522,7 +3522,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");