usb: usb_bam: vote for hsic lpm only after consumer release
This change fix the handshake between hsic and ipa resource manager for
case of concurrency cases of hsic/usb in which hsic consumer might not be
released. Tie the hsic lpm with the consumer release and request
notifications from the resource manager.
Change-Id: I6ec6e58c2bd7de6818355f42a077935c00218fdb
Signed-off-by: Ido Shayevitz <idos@codeaurora.org>
diff --git a/drivers/platform/msm/usb_bam.c b/drivers/platform/msm/usb_bam.c
index af5442a..bed8e07 100644
--- a/drivers/platform/msm/usb_bam.c
+++ b/drivers/platform/msm/usb_bam.c
@@ -170,6 +170,7 @@
static struct usb_bam_ctx_type ctx;
static struct device *hsic_host_dev;
+static bool hsic_host_dev_resumed_from_cons_request;
static int __usb_bam_register_wake_cb(u8 idx, int (*callback)(void *user),
void *param, bool trigger_cb_per_pipe);
@@ -888,6 +889,8 @@
break;
case HSIC_BAM:
+ hsic_host_dev_resumed_from_cons_request = true;
+
usb_bam_resume_hsic_host();
/*
@@ -937,13 +940,29 @@
}
spin_unlock(&usb_bam_lock);
- spin_lock(&usb_bam_ipa_handshake_info_lock);
- if (cur_bam == HSUSB_BAM && info.bus_suspend)
- queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
- spin_unlock(&usb_bam_ipa_handshake_info_lock);
+ if (cur_bam == HSUSB_BAM) {
+ spin_lock(&usb_bam_ipa_handshake_info_lock);
+ if (info.bus_suspend)
+ queue_work(ctx.usb_bam_wq, &info.finish_suspend_work);
+ spin_unlock(&usb_bam_ipa_handshake_info_lock);
- pr_debug("%s: EINPROGRESS cons_release", __func__);
- return -EINPROGRESS;
+ pr_debug("%s: EINPROGRESS cons_release", __func__);
+ return -EINPROGRESS;
+ } else if (cur_bam == HSIC_BAM) {
+
+ /*
+ * 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 && !info.in_lpm[HSIC_BAM]) {
+ 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;
+ }
+ }
+
+ return 0;
}
static int hsic_cons_release_resource(void)
@@ -1286,6 +1305,9 @@
void msm_bam_wait_for_hsic_prod_granted(void)
{
+ if (hsic_host_dev_resumed_from_cons_request)
+ return;
+
ctx.is_bam_inactivity[HSIC_BAM] = false;
/* Get back to resume state including wakeup ipa */
@@ -1303,8 +1325,11 @@
* and clocked on. Therefore we can now set the inactivity
* timer to the hsic bam hw.
*/
- if (ctx.inactivity_timer_ms[HSIC_BAM])
+ if (ctx.inactivity_timer_ms[HSIC_BAM] &&
+ !hsic_host_dev_resumed_from_cons_request)
usb_bam_set_inactivity_timer(HSIC_BAM);
+
+ hsic_host_dev_resumed_from_cons_request = false;
}
bool msm_bam_hsic_lpm_ok(void)
@@ -1317,18 +1342,6 @@
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
@@ -1338,9 +1351,6 @@
*/
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] ==
@@ -1369,14 +1379,18 @@
return true;
}
- /* We not allow lpm, therefore renew our vote here */
+ /* We don't 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);
+ pr_err("%s: Not allow lpm while ref count=0\n",
+ __func__);
+ pr_err("%s: inactivity=%d, c_s=%d p_s=%d lpm=%d\n",
+ __func__, ctx.is_bam_inactivity[HSIC_BAM],
+ info.cur_cons_state[HSIC_BAM],
+ info.cur_prod_state[HSIC_BAM],
+ info.in_lpm[HSIC_BAM]);
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);
@@ -1623,21 +1637,28 @@
}
spin_unlock(&usb_bam_lock);
+ /* Notify about the inactivity to the USB class driver */
+ if (callback)
+ callback(param);
+
+ wait_for_prod_release(pipe_connect->bam_type);
+ pr_debug("%s: complete wait on hsic producer s=%d\n",
+ __func__, info.cur_prod_state[pipe_connect->bam_type]);
+
/*
- * Allow to go to lpm for now. Actual state will be checked
- * in msm_bam_hsic_lpm_ok() just before going to lpm.
+ * Allow to go to lpm for now if also consumer is down.
+ * If consumer is up, we will wait to the release consumer
+ * notification.
*/
- if (hsic_host_dev) {
+ if (hsic_host_dev &&
+ info.cur_cons_state[HSIC_BAM] ==
+ IPA_RM_RESOURCE_RELEASED && !info.in_lpm[HSIC_BAM]) {
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);
-
break;
default:
pr_err("%s: unknown usb bam event type %d\n", __func__,
@@ -1671,21 +1692,6 @@
*/
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);
}