ehci: hsic: add suspend/resume handshake with ipa resource manager
This change ensure correct sequence with the ipa resource manager
to obtain or release the producer and consumer resources upon
hsic host suspend/resume sequences which involve entering/exiting
to low power mode.
Change-Id: Iec77b9a24a3192a19de93c813b416baca26c7a77
Signed-off-by: Ido Shayevitz <idos@codeaurora.org>
diff --git a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
index 8ce31d9..b0d6b4d 100644
--- a/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
+++ b/Documentation/devicetree/bindings/usb/msm-ehci-hsic.txt
@@ -40,6 +40,8 @@
DATA GPIO PAD.
- qcom,phy-sof-workaround : If present then HSIC PHY has h/w BUGs related to
SOFs. Software workarounds are required for the same.
+- hsic,consider-ipa-handshake: If present then hsic low power mode is
+ depend on suitable handshake with the IPA peer.
- Refer to "Documentation/devicetree/bindings/arm/msm/msm_bus.txt" for
below optional properties:
@@ -71,6 +73,7 @@
hsic,ignore-cal-pad-config;
hsic,strobe-pad-offset = <0x2050>;
hsic,data-pad-offset = <0x2054>;
+ hsic,consider-ipa-handshake;
qcom,msm-bus,name = "hsic";
qcom,msm-bus,num-cases = <2>;
diff --git a/arch/arm/mach-msm/include/mach/usb_bam.h b/arch/arm/mach-msm/include/mach/usb_bam.h
index 5ecc63b..bc76f56 100644
--- a/arch/arm/mach-msm/include/mach/usb_bam.h
+++ b/arch/arm/mach-msm/include/mach/usb_bam.h
@@ -126,6 +126,7 @@
struct sps_mem_buffer desc_mem_buf;
struct usb_bam_event_info event;
bool enabled;
+ bool suspended;
int ipa_clnt_hdl;
void *priv;
int (*activity_notify)(void *priv);
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index fc85dba..4c59a2a 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -133,11 +133,11 @@
enum ipa_rm_event cur_prod_state[MAX_BAMS];
enum ipa_rm_event cur_cons_state[MAX_BAMS];
- int lpm_wait_handshake;
+ bool lpm_wait_handshake[MAX_BAMS];
int connect_complete;
bool lpm_wait_pipes;
int bus_suspend;
- bool in_lpm;
+ bool in_lpm[MAX_BAMS];
int (*wake_cb)(void *);
void *wake_param;
@@ -169,8 +169,31 @@
static struct usb_bam_pipe_connect *usb_bam_connections;
static struct usb_bam_ctx_type ctx;
+static struct device *hsic_host_dev;
+
static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param, bool trigger_cb_per_pipe);
+static void wait_for_prod_release(enum usb_bam cur_bam);
+static void wait_for_cons_release(enum usb_bam cur_bam);
+
+void msm_bam_set_hsic_host_dev(struct device *dev)
+{
+ if (dev) {
+ /* Hold the device until allowing lpm */
+ info.in_lpm[HSIC_BAM] = false;
+ pr_debug("%s: Getting hsic device %x\n", __func__,
+ (int)dev);
+ pm_runtime_get(dev);
+ } else if (hsic_host_dev) {
+ pr_debug("%s: Putting hsic device %x\n", __func__,
+ (int)hsic_host_dev);
+ /* Just free previous device*/
+ info.in_lpm[HSIC_BAM] = true;
+ pm_runtime_put(hsic_host_dev);
+ }
+
+ hsic_host_dev = dev;
+}
static int get_bam_type_from_core_name(const char *name)
{
@@ -209,6 +232,8 @@
struct sps_pipe *pipe = NULL;
int i;
+ pr_debug("%s: enter\n", __func__);
+
/*
* Since we configure global incativity timer for all pipes
* and not per each pipe, it is enough to use some pipe
@@ -217,14 +242,15 @@
*/
for (i = 0; i < ctx.max_connections; i++) {
pipe_connect = &usb_bam_connections[i];
- if (pipe_connect->bam_type == bam) {
+ if (pipe_connect->bam_type == bam &&
+ pipe_connect->enabled) {
pipe = ctx.usb_bam_sps.sps_pipes[i];
break;
}
}
if (!pipe) {
- pr_err("%s: Bam %s has no pipes\n", __func__,
+ pr_warning("%s: Bam %s has no connected pipes\n", __func__,
bam_enable_strings[bam]);
return;
}
@@ -540,16 +566,6 @@
goto error;
}
- spin_lock(&usb_bam_lock);
-
- /* Set global inactivity timer upon first pipe connection */
- if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0 &&
- ctx.inactivity_timer_ms[pipe_connect->bam_type] &&
- pipe_connect->inactivity_notify)
- usb_bam_set_inactivity_timer(pipe_connect->bam_type);
-
- spin_unlock(&usb_bam_lock);
-
return 0;
error:
@@ -622,7 +638,7 @@
BUG_ON(trans == NULL);
pr_debug("%s: Going to LPM\n", __func__);
spin_lock(&usb_bam_ipa_handshake_info_lock);
- info.lpm_wait_handshake = false;
+ info.lpm_wait_handshake[HSUSB_BAM] = false;
info.lpm_wait_pipes = 0;
if (disconnect)
pm_runtime_put_noidle(trans->dev);
@@ -813,8 +829,40 @@
return;
}
+static void usb_bam_resume_hsic_host(void)
+{
+ int i;
+ struct usb_bam_pipe_connect *pipe_iter;
+
+ spin_lock(&usb_bam_lock);
+
+ /* Exit from "full suspend" in case of hsic host */
+ if (hsic_host_dev && info.in_lpm[HSIC_BAM]) {
+ pr_debug("%s: Getting hsic device %x\n", __func__,
+ (int)hsic_host_dev);
+ pm_runtime_get(hsic_host_dev);
+ info.in_lpm[HSIC_BAM] = false;
+
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_iter = &usb_bam_connections[i];
+ if (pipe_iter->bam_type == HSIC_BAM &&
+ pipe_iter->enabled &&
+ pipe_iter->suspended) {
+ spin_unlock(&usb_bam_lock);
+ ipa_resume(pipe_iter->ipa_clnt_hdl);
+ pipe_iter->suspended = false;
+ spin_lock(&usb_bam_lock);
+ }
+ }
+ }
+
+ spin_unlock(&usb_bam_lock);
+}
+
static int cons_request_resource(enum usb_bam cur_bam)
{
+ int ret = -EINPROGRESS;
+
pr_debug("%s: Request %s_CONS resource\n",
__func__, bam_enable_strings[cur_bam]);
@@ -823,29 +871,44 @@
complete_all(&info.cons_avail[cur_bam]);
spin_lock(&usb_bam_lock);
- if (ctx.pipes_enabled_per_bam[cur_bam] && info.connect_complete &&
- !info.bus_suspend && !info.prod_stopped) {
- spin_unlock(&usb_bam_lock);
- spin_unlock(&usb_bam_ipa_handshake_info_lock);
- pr_debug("%s: ACK on cons_request", __func__);
- return 0;
+
+ switch (cur_bam) {
+ case HSUSB_BAM:
+ if (ctx.pipes_enabled_per_bam[HSUSB_BAM] &&
+ info.connect_complete &&
+ !info.cons_stopped && !info.prod_stopped) {
+ pr_debug("%s: ACK on cons_request", __func__);
+ ret = 0;
+ } else if (ctx.pipes_enabled_per_bam[HSUSB_BAM] &&
+ info.connect_complete && info.bus_suspend) {
+ info.bus_suspend = 0;
+ if (info.wake_cb)
+ info.wake_cb(info.wake_param);
+ }
+
+ break;
+ case HSIC_BAM:
+ usb_bam_resume_hsic_host();
+
+ /*
+ * Return sucess if there are pipes connected
+ * and not in lpm
+ */
+ if (ctx.pipes_enabled_per_bam[cur_bam] &&
+ !info.in_lpm[cur_bam])
+ ret = 0;
+ break;
+ case SSUSB_BAM:
+ default:
+ break;
}
- /* A2 wakeup from LPM */
- if (cur_bam == HSUSB_BAM && ctx.pipes_enabled_per_bam[cur_bam] &&
- info.connect_complete && info.bus_suspend) {
- info.bus_suspend = 0;
- spin_unlock(&usb_bam_lock);
- spin_unlock(&usb_bam_ipa_handshake_info_lock);
- if (info.wake_cb)
- info.wake_cb(info.wake_param);
- } else {
- spin_unlock(&usb_bam_lock);
- spin_unlock(&usb_bam_ipa_handshake_info_lock);
- }
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ spin_unlock(&usb_bam_lock);
- pr_debug("%s: EINPROGRESS on cons_request", __func__);
- return -EINPROGRESS;
+ if (ret == -EINPROGRESS)
+ pr_debug("%s: EINPROGRESS on cons_request", __func__);
+ return ret;
}
static int usb_cons_request_resource(void)
@@ -934,7 +997,7 @@
}
}
-static void wait_for_prod_granted(enum usb_bam cur_bam)
+static void wait_for_prod_granted(enum usb_bam cur_bam, bool start_cons)
{
int ret;
@@ -948,7 +1011,8 @@
__func__);
init_completion(&info.prod_avail[cur_bam]);
- init_completion(&info.cons_avail[cur_bam]);
+ if (start_cons)
+ init_completion(&info.cons_avail[cur_bam]);
ret = ipa_rm_request_resource(ipa_rm_resource_prod[cur_bam]);
if (!ret) {
@@ -1129,7 +1193,7 @@
}
spin_lock(&usb_bam_ipa_handshake_info_lock);
- info.lpm_wait_handshake = true;
+ info.lpm_wait_handshake[HSUSB_BAM] = true;
spin_unlock(&usb_bam_ipa_handshake_info_lock);
wait_for_prod_release(HSUSB_BAM);
@@ -1156,10 +1220,10 @@
mutex_unlock(&info.suspend_resume_mutex);
return;
}
- info.lpm_wait_handshake = true;
+ info.lpm_wait_handshake[HSUSB_BAM] = true;
spin_unlock(&usb_bam_ipa_handshake_info_lock);
- wait_for_prod_granted(HSUSB_BAM);
+ wait_for_prod_granted(HSUSB_BAM, true);
wait_for_cons_granted(HSUSB_BAM);
if (info.cons_stopped) {
ipa_resume_pipes();
@@ -1213,13 +1277,115 @@
if (cur_bam != HSUSB_BAM)
return;
- info.in_lpm = false;
+ info.in_lpm[HSUSB_BAM] = false;
spin_lock(&usb_bam_ipa_handshake_info_lock);
info.bus_suspend = 0;
spin_unlock(&usb_bam_ipa_handshake_info_lock);
queue_work(ctx.usb_bam_wq, &info.resume_work);
}
+void msm_bam_wait_for_hsic_prod_granted(void)
+{
+ ctx.is_bam_inactivity[HSIC_BAM] = false;
+
+ /* Get back to resume state including wakeup ipa */
+ usb_bam_resume_hsic_host();
+
+ /* Ensure getting the producer resource */
+ wait_for_prod_granted(HSIC_BAM, false);
+}
+
+void msm_bam_hsic_notify_on_resume(void)
+{
+ /*
+ * This function is called to notify the usb bam driver
+ * that the hsic core and hsic bam hw are fully resumed
+ * and clocked on. Therefore we can now set the inactivity
+ * timer to the hsic bam hw.
+ */
+ if (ctx.inactivity_timer_ms[HSIC_BAM])
+ usb_bam_set_inactivity_timer(HSIC_BAM);
+}
+
+bool msm_bam_hsic_lpm_ok(void)
+{
+ int i;
+ struct usb_bam_pipe_connect *pipe_iter;
+
+ if (hsic_host_dev) {
+
+ pr_debug("%s: Starting hsic full suspend sequence\n",
+ __func__);
+
+ info.lpm_wait_handshake[HSIC_BAM] = true;
+
+ wait_for_prod_release(HSIC_BAM);
+ pr_debug("%s: complete wait on hsic producer s=%d\n",
+ __func__, info.cur_prod_state[HSIC_BAM]);
+
+ wait_for_cons_release(HSIC_BAM);
+ pr_debug("%s: complete wait on hsic consumer s=%d\n",
+ __func__, info.cur_cons_state[HSIC_BAM]);
+
+ info.lpm_wait_handshake[HSIC_BAM] = false;
+
+ /*
+ * Start low power mode by releasing the device
+ * only in case that indeed the resources were released
+ * and we are still in inactivity state (wake event
+ * have not been occured while we were waiting to the
+ * resources release)
+ */
+ spin_lock(&usb_bam_lock);
+
+ pr_debug("%s: goto lpm?, inactivity=%d\n",
+ __func__, ctx.is_bam_inactivity[HSIC_BAM]);
+
+ if (info.cur_cons_state[HSIC_BAM] ==
+ IPA_RM_RESOURCE_RELEASED &&
+ info.cur_prod_state[HSIC_BAM] ==
+ IPA_RM_RESOURCE_RELEASED &&
+ ctx.is_bam_inactivity[HSIC_BAM] && info.in_lpm[HSIC_BAM]) {
+
+ /* HSIC host will go now to lpm */
+ pr_debug("%s: vote for suspend hsic %x\n",
+ __func__, (int)hsic_host_dev);
+
+ for (i = 0; i < ctx.max_connections; i++) {
+ pipe_iter =
+ &usb_bam_connections[i];
+ if (pipe_iter->bam_type == HSIC_BAM &&
+ pipe_iter->enabled &&
+ !pipe_iter->suspended) {
+ spin_unlock(&usb_bam_lock);
+ ipa_suspend(
+ pipe_iter->ipa_clnt_hdl);
+ pipe_iter->suspended = true;
+ spin_lock(&usb_bam_lock);
+ }
+ }
+
+ spin_unlock(&usb_bam_lock);
+ return true;
+ }
+
+ /* We not allow lpm, therefore renew our vote here */
+ if (info.in_lpm[HSIC_BAM]) {
+ pr_debug("%s: Getting hsic device %x\n", __func__,
+ (int)hsic_host_dev);
+ pm_runtime_get(hsic_host_dev);
+ info.in_lpm[HSIC_BAM] = false;
+ spin_unlock(&usb_bam_lock);
+ wait_for_prod_granted(HSIC_BAM, false);
+ } else
+ spin_unlock(&usb_bam_lock);
+
+ return false;
+ }
+
+ return true;
+}
+
int usb_bam_connect_ipa(struct usb_bam_connect_ipa_params *ipa_params)
{
u8 idx;
@@ -1255,52 +1421,77 @@
}
pr_debug("%s: enter", __func__);
- mutex_lock(&info.suspend_resume_mutex);
- spin_lock(&usb_bam_lock);
- if (ctx.pipes_enabled_per_bam[cur_bam] == 0) {
- spin_unlock(&usb_bam_lock);
- if (cur_bam == HSUSB_BAM) {
+ if (cur_bam == HSUSB_BAM) {
+ mutex_lock(&info.suspend_resume_mutex);
+
+ spin_lock(&usb_bam_lock);
+ if (ctx.pipes_enabled_per_bam[HSUSB_BAM] == 0) {
+ spin_unlock(&usb_bam_lock);
spin_lock(&usb_bam_ipa_handshake_info_lock);
- info.lpm_wait_handshake = 1;
+ info.lpm_wait_handshake[HSUSB_BAM] = true;
info.connect_complete = 0;
info.lpm_wait_pipes = 1;
info.bus_suspend = 0;
info.cons_stopped = 0;
info.prod_stopped = 0;
spin_unlock(&usb_bam_ipa_handshake_info_lock);
- }
- usb_bam_resume_core(cur_bam);
- } else
- spin_unlock(&usb_bam_lock);
+ usb_bam_resume_core(cur_bam);
+ } else
+ spin_unlock(&usb_bam_lock);
+ }
/* Check if BAM requires RESET before connect and reset first pipe */
spin_lock(&usb_bam_lock);
if ((pdata->reset_on_connect[cur_bam] == true) &&
- (ctx.pipes_enabled_per_bam[cur_bam] == 0))
- sps_device_reset(ctx.h_bam[cur_bam]);
+ (ctx.pipes_enabled_per_bam[cur_bam] == 0)) {
+ spin_unlock(&usb_bam_lock);
+ sps_device_reset(ctx.h_bam[cur_bam]);
+
+ /* On re-connect assume out from lpm for HSIC BAM */
+ if (cur_bam == HSIC_BAM && hsic_host_dev &&
+ info.in_lpm[HSIC_BAM]) {
+ pr_debug("%s: Getting hsic device %x\n",
+ __func__, (int)hsic_host_dev);
+ pm_runtime_get(hsic_host_dev);
+ }
+
+ /* On re-connect assume out from lpm for all BAMs */
+ info.in_lpm[cur_bam] = false;
+ } else
spin_unlock(&usb_bam_lock);
if (ipa_params->dir == USB_TO_PEER_PERIPHERAL) {
pr_debug("%s: Starting connect sequence\n", __func__);
- wait_for_prod_granted(cur_bam);
+ wait_for_prod_granted(cur_bam, true);
}
ret = connect_pipe_ipa(idx, ipa_params);
if (ret) {
pr_err("%s: pipe connection failure\n", __func__);
- mutex_unlock(&info.suspend_resume_mutex);
+ if (cur_bam == HSUSB_BAM)
+ mutex_unlock(&info.suspend_resume_mutex);
return ret;
}
spin_lock(&usb_bam_lock);
pipe_connect->enabled = 1;
+ pipe_connect->suspended = 0;
+
+ /* Set global inactivity timer upon first pipe connection */
+ if (ctx.pipes_enabled_per_bam[pipe_connect->bam_type] == 0 &&
+ ctx.inactivity_timer_ms[pipe_connect->bam_type] &&
+ pipe_connect->inactivity_notify)
+ usb_bam_set_inactivity_timer(pipe_connect->bam_type);
+
ctx.pipes_enabled_per_bam[cur_bam] += 1;
spin_unlock(&usb_bam_lock);
if (ipa_params->dir == PEER_PERIPHERAL_TO_USB && cur_bam == HSUSB_BAM)
wait_for_cons_granted(cur_bam);
- mutex_unlock(&info.suspend_resume_mutex);
+ if (cur_bam == HSUSB_BAM)
+ mutex_unlock(&info.suspend_resume_mutex);
+
pr_debug("%s: done", __func__);
return 0;
@@ -1337,7 +1528,7 @@
container_of(w, struct usb_bam_event_info, event_w);
struct usb_bam_pipe_connect *pipe_connect =
container_of(event_info, struct usb_bam_pipe_connect, event);
- struct usb_bam_pipe_connect *pipe_connect_iter;
+ struct usb_bam_pipe_connect *pipe_iter;
int (*callback)(void *priv);
void *param = NULL;
@@ -1347,8 +1538,33 @@
pr_debug("%s recieved USB_BAM_EVENT_WAKEUP\n", __func__);
+ /*
+ * Make sure the PROD resource is granted before
+ * wakeup hsic host class driver (done by the callback below)
+ */
+ if (pipe_connect->peer_bam == IPA_P_BAM &&
+ pipe_connect->bam_type == HSIC_BAM &&
+ info.cur_prod_state[HSIC_BAM] != IPA_RM_RESOURCE_GRANTED) {
+ wait_for_prod_granted(HSIC_BAM, false);
+ }
+
+ /*
+ * Check if need to resume the hsic host.
+ * On one hand, since we got the wakeup interrupt
+ * the hsic bam clocks are already enabled, so no need
+ * to actualluy resume the hardware... However, we still need
+ * to update the usb bam driver state (to set in_lpm=false),
+ * and to wake ipa (ipa_resume) and to hold again the hsic host
+ * device again to avoid it going to low poer mode next time
+ * until we complete releasing the hsic consumer and producer
+ * resources against the ipa resource manager.
+ */
+ if (pipe_connect->bam_type == HSIC_BAM)
+ usb_bam_resume_hsic_host();
+
/* Notify about wakeup / activity of the bam */
- event_info->callback(event_info->param);
+ if (event_info->callback)
+ event_info->callback(event_info->param);
/*
* Reset inactivity timer counter if this pipe's bam
@@ -1359,12 +1575,14 @@
usb_bam_set_inactivity_timer(pipe_connect->bam_type);
spin_unlock(&usb_bam_lock);
- /* A2 wakeup not from LPM (CONS was up) */
- wait_for_prod_granted(pipe_connect->bam_type);
- if (info.start) {
- pr_debug("%s: Enqueue PROD transfer", __func__);
- info.start(info.start_stop_param,
- USB_TO_PEER_PERIPHERAL);
+ if (pipe_connect->bam_type == HSUSB_BAM) {
+ /* A2 wakeup not from LPM (CONS was up) */
+ wait_for_prod_granted(pipe_connect->bam_type, true);
+ if (info.start) {
+ pr_debug("%s: Enqueue PROD transfer", __func__);
+ info.start(info.start_stop_param,
+ USB_TO_PEER_PERIPHERAL);
+ }
}
break;
@@ -1389,21 +1607,34 @@
*/
spin_lock(&usb_bam_lock);
for (i = 0; i < ctx.max_connections; i++) {
- pipe_connect_iter = &usb_bam_connections[i];
- if (pipe_connect_iter->bam_type ==
+ pipe_iter = &usb_bam_connections[i];
+ if (pipe_iter->bam_type ==
pipe_connect->bam_type &&
- pipe_connect_iter->dir ==
+ pipe_iter->dir ==
PEER_PERIPHERAL_TO_USB &&
- pipe_connect_iter->enabled) {
+ pipe_iter->enabled) {
+ pr_debug("%s: Register wakeup on pipe %x\n",
+ __func__, (int)pipe_iter);
__usb_bam_register_wake_cb(i,
- pipe_connect_iter->activity_notify,
- pipe_connect_iter->priv,
+ pipe_iter->activity_notify,
+ pipe_iter->priv,
false);
}
}
spin_unlock(&usb_bam_lock);
- /* Notify about the inactivity */
+ /*
+ * Allow to go to lpm for now. Actual state will be checked
+ * in msm_bam_hsic_lpm_ok() just before going to lpm.
+ */
+ if (hsic_host_dev) {
+ pr_debug("%s: Putting hsic device %x\n", __func__,
+ (int)hsic_host_dev);
+ pm_runtime_put(hsic_host_dev);
+ info.in_lpm[HSIC_BAM] = true;
+ }
+
+ /* Notify about the inactivity to the USB class driver */
if (callback)
callback(param);
@@ -1422,13 +1653,14 @@
container_of(event_info,
struct usb_bam_pipe_connect,
event);
+ enum usb_bam bam = pipe_connect->bam_type;
spin_lock(&usb_bam_lock);
if (event_info->type == USB_BAM_EVENT_WAKEUP_PIPE)
queue_work(ctx.usb_bam_wq, &event_info->event_w);
else if (event_info->type == USB_BAM_EVENT_WAKEUP &&
- ctx.is_bam_inactivity[pipe_connect->bam_type]) {
+ ctx.is_bam_inactivity[bam]) {
/*
* Sps wake event is per pipe, so usb_bam_wake_cb is
@@ -1437,7 +1669,23 @@
* Therefore, the first pipe that awaked will be considered
* as global bam wake event.
*/
- ctx.is_bam_inactivity[pipe_connect->bam_type] = false;
+ ctx.is_bam_inactivity[bam] = false;
+
+ /*
+ * In case that this wakeup event occured while we are
+ * waiting to release of the resurces in order to get into
+ * low power mode, just cancle the waiting.
+ */
+ if (info.lpm_wait_handshake[bam]) {
+ pr_debug("%s: cancel waiting for lpm\n", __func__);
+ if (info.cur_prod_state[bam] !=
+ IPA_RM_RESOURCE_RELEASED)
+ complete_all(&info.prod_released[bam]);
+ if (info.cur_cons_state[bam] !=
+ IPA_RM_RESOURCE_RELEASED)
+ complete_all(&info.cons_released[bam]);
+ }
+
queue_work(ctx.usb_bam_wq, &event_info->event_w);
}
@@ -1687,6 +1935,10 @@
idx = ipa_params->dst_idx;
pipe_connect = &usb_bam_connections[idx];
+ pipe_connect->activity_notify = NULL;
+ pipe_connect->inactivity_notify = NULL;
+ pipe_connect->priv = NULL;
+
/* Do the release handshake with the A2 via RM */
cur_bam = pipe_connect->bam_type;
info.lpm_wait_pipes = 1;
@@ -1716,6 +1968,11 @@
if (ipa_params->cons_clnt_hdl) {
idx = ipa_params->src_idx;
pipe_connect = &usb_bam_connections[idx];
+
+ pipe_connect->activity_notify = NULL;
+ pipe_connect->inactivity_notify = NULL;
+ pipe_connect->priv = NULL;
+
cur_bam = pipe_connect->bam_type;
wait_for_cons_release(cur_bam);
/* close IPA -> USB pipe */
@@ -1839,9 +2096,11 @@
/*
* Notify inactivity once, Since it is global
- * for all pipes on bam.
+ * for all pipes on bam. Notify only if we have
+ * connected pipes.
*/
- if (pipe_connect->bam_type == bam) {
+ if (pipe_connect->bam_type == bam &&
+ pipe_connect->enabled) {
event_info = &pipe_connect->event;
event_info->type = USB_BAM_EVENT_INACTIVITY;
event_info->param = pipe_connect->priv;
@@ -2190,7 +2449,8 @@
/* Apply new timer setting if bam has running pipes */
if (ctx.inactivity_timer_ms[bam] != timer_d) {
ctx.inactivity_timer_ms[bam] = timer_d;
- if (ctx.pipes_enabled_per_bam[bam] > 0)
+ if (ctx.pipes_enabled_per_bam[bam] > 0 &&
+ !info.in_lpm[bam])
usb_bam_set_inactivity_timer(bam);
}
@@ -2263,6 +2523,7 @@
complete(&info.prod_released[i]);
info.cur_prod_state[i] = IPA_RM_RESOURCE_RELEASED;
info.cur_cons_state[i] = IPA_RM_RESOURCE_RELEASED;
+ info.lpm_wait_handshake[i] = false;
}
INIT_WORK(&info.resume_work, usb_bam_finish_resume);
@@ -2360,12 +2621,12 @@
bool msm_bam_lpm_ok(void)
{
spin_lock(&usb_bam_ipa_handshake_info_lock);
- if (info.lpm_wait_handshake || info.lpm_wait_pipes) {
+ if (info.lpm_wait_handshake[HSUSB_BAM] || info.lpm_wait_pipes) {
spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Scheduling LPM for later\n", __func__);
return 0;
} else {
- info.in_lpm = 1;
+ info.in_lpm[HSUSB_BAM] = true;
spin_unlock(&usb_bam_ipa_handshake_info_lock);
pr_err("%s: Going to LPM now\n", __func__);
return 1;
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index d1d0f91..0ea9778 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -752,6 +752,19 @@
return -EBUSY;
}
+ if (pdata->consider_ipa_handshake) {
+ dev_dbg(mehci->dev, "%s:Wait for resources release\n",
+ __func__);
+ if (!msm_bam_hsic_lpm_ok()) {
+ dev_dbg(mehci->dev, "%s:Prod+Cons not released\n",
+ __func__);
+ enable_irq(hcd->irq);
+ return -EBUSY;
+ }
+ dev_dbg(mehci->dev, "%s:Prod+Cons resources released\n",
+ __func__);
+ }
+
/*
* PHY may take some time or even fail to enter into low power
* mode (LPM). Hence poll for 500 msec and reset the PHY and link
@@ -829,7 +842,7 @@
wake_unlock(&mehci->wlock);
- dev_dbg(mehci->dev, "HSIC-USB in low power mode\n");
+ dev_info(mehci->dev, "HSIC-USB in low power mode\n");
return 0;
}
@@ -848,6 +861,14 @@
return 0;
}
+ if (pdata->consider_ipa_handshake) {
+ dev_dbg(mehci->dev, "%s:Wait for producer resource\n",
+ __func__);
+ msm_bam_wait_for_hsic_prod_granted();
+ dev_dbg(mehci->dev, "%s:Producer resource obtained\n",
+ __func__);
+ }
+
/* Handles race with Async interrupt */
disable_irq(hcd->irq);
@@ -933,7 +954,13 @@
}
enable_irq(hcd->irq);
- dev_dbg(mehci->dev, "HSIC-USB exited from low power mode\n");
+ dev_info(mehci->dev, "HSIC-USB exited from low power mode\n");
+
+ if (pdata->consider_ipa_handshake) {
+ dev_dbg(mehci->dev, "%s:Notify usb bam on resume complete\n",
+ __func__);
+ msm_bam_hsic_notify_on_resume();
+ }
return 0;
}
@@ -1853,6 +1880,8 @@
"qcom,enable-hbm");
pdata->disable_park_mode = (of_property_read_bool(node,
"qcom,disable-park-mode"));
+ pdata->consider_ipa_handshake = (of_property_read_bool(node,
+ "hsic,consider-ipa-handshake"));
return pdata;
}
@@ -2092,6 +2121,8 @@
if (mehci->enable_hbm)
hbm_init(hcd, pdata->disable_park_mode);
+ msm_bam_set_hsic_host_dev(&pdev->dev);
+
return 0;
destroy_wq:
@@ -2115,6 +2146,8 @@
struct msm_hsic_hcd *mehci = hcd_to_hsic(hcd);
struct msm_hsic_host_platform_data *pdata = mehci->dev->platform_data;
+ msm_bam_set_hsic_host_dev(NULL);
+
/* If the device was removed no need to call pm_runtime_disable */
if (pdev->dev.power.power_state.event != PM_EVENT_INVALID)
pm_runtime_disable(&pdev->dev);
diff --git a/include/linux/usb/msm_hsusb.h b/include/linux/usb/msm_hsusb.h
index 4ae3b79..209062b 100644
--- a/include/linux/usb/msm_hsusb.h
+++ b/include/linux/usb/msm_hsusb.h
@@ -424,6 +424,7 @@
bool pool_64_bit_align;
bool enable_hbm;
bool disable_park_mode;
+ bool consider_ipa_handshake;
};
struct msm_usb_host_platform_data {
@@ -465,8 +466,16 @@
};
#ifdef CONFIG_USB_BAM
bool msm_bam_lpm_ok(void);
+void msm_bam_set_hsic_host_dev(struct device *dev);
+void msm_bam_wait_for_hsic_prod_granted(void);
+bool msm_bam_hsic_lpm_ok(void);
+void msm_bam_hsic_notify_on_resume(void);
#else
static inline bool msm_bam_lpm_ok(void) { return true; }
+static inline void msm_bam_set_hsic_host_dev(struct device *dev) {}
+static inline void msm_bam_wait_for_hsic_prod_granted(void) {}
+static inline bool msm_bam_hsic_lpm_ok(void) { return true; }
+static inline void msm_bam_hsic_notify_on_resume(void) {}
#endif
#ifdef CONFIG_USB_CI13XXX_MSM
void msm_hw_bam_disable(bool bam_disable);