msm: ipa: Fix wakelock issue
There is a possibility that wakelock is not acquired when
polling state is set and we allow system to go to suspend.
Make a change to acquire/release the wakelock based on the
polling state to not allow system to go to suspend.
b/24338185
Change-Id: Iec4e7511e9a03b4f9911b280ce4ddc0e913b5185
Acked-by: Chaitanya Pratapa <cpratapa@qti.qualcomm.com>
Signed-off-by: Ravinder Konka <rkonka@codeaurora.org>
Signed-off-by: Niranjan Pendharkar <npendhar@codeaurora.org>
diff --git a/drivers/platform/msm/ipa/ipa.c b/drivers/platform/msm/ipa/ipa.c
index d06a37d..0909175 100644
--- a/drivers/platform/msm/ipa/ipa.c
+++ b/drivers/platform/msm/ipa/ipa.c
@@ -2560,6 +2560,45 @@
ipa_active_clients_unlock();
}
+/**
+* ipa_inc_acquire_wakelock() - Increase active clients counter, and
+* acquire wakelock if necessary
+*
+* Return codes:
+* None
+*/
+void ipa_inc_acquire_wakelock(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipa_ctx->wakelock_ref_cnt.spinlock, flags);
+ ipa_ctx->wakelock_ref_cnt.cnt++;
+ if (ipa_ctx->wakelock_ref_cnt.cnt == 1)
+ __pm_stay_awake(&ipa_ctx->w_lock);
+ IPADBG("active wakelock ref cnt = %d\n", ipa_ctx->wakelock_ref_cnt.cnt);
+ spin_unlock_irqrestore(&ipa_ctx->wakelock_ref_cnt.spinlock, flags);
+}
+
+/**
+ * ipa_dec_release_wakelock() - Decrease active clients counter
+ *
+ * In case if the ref count is 0, release the wakelock.
+ *
+ * Return codes:
+ * None
+ */
+void ipa_dec_release_wakelock(void)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&ipa_ctx->wakelock_ref_cnt.spinlock, flags);
+ ipa_ctx->wakelock_ref_cnt.cnt--;
+ IPADBG("active wakelock ref cnt = %d\n", ipa_ctx->wakelock_ref_cnt.cnt);
+ if (ipa_ctx->wakelock_ref_cnt.cnt == 0)
+ __pm_relax(&ipa_ctx->w_lock);
+ spin_unlock_irqrestore(&ipa_ctx->wakelock_ref_cnt.spinlock, flags);
+}
+
static int ipa_setup_bam_cfg(const struct ipa_plat_drv_res *res)
{
void *ipa_bam_mmio;
@@ -3319,6 +3358,10 @@
goto fail_init_hw;
}
+ /* Create a wakeup source. */
+ wakeup_source_init(&ipa_ctx->w_lock, "IPA_WS");
+ spin_lock_init(&ipa_ctx->wakelock_ref_cnt.spinlock);
+
/* Initialize IPA RM (resource manager) */
result = ipa_rm_initialize();
if (result) {
diff --git a/drivers/platform/msm/ipa/ipa_dp.c b/drivers/platform/msm/ipa/ipa_dp.c
index d0aae56..d61150f 100644
--- a/drivers/platform/msm/ipa/ipa_dp.c
+++ b/drivers/platform/msm/ipa/ipa_dp.c
@@ -222,6 +222,7 @@
}
atomic_set(&sys->curr_polling_state, 0);
ipa_handle_tx_core(sys, true, false);
+ ipa_dec_release_wakelock();
return;
fail:
@@ -649,6 +650,7 @@
IPAERR("sps_set_config() failed %d\n", ret);
break;
}
+ ipa_inc_acquire_wakelock();
atomic_set(&sys->curr_polling_state, 1);
queue_work(sys->wq, &sys->work);
}
@@ -762,6 +764,7 @@
}
atomic_set(&sys->curr_polling_state, 0);
ipa_handle_rx_core(sys, true, false);
+ ipa_dec_release_wakelock();
return;
fail:
@@ -806,6 +809,7 @@
IPAERR("sps_set_config() failed %d\n", ret);
break;
}
+ ipa_inc_acquire_wakelock();
atomic_set(&sys->curr_polling_state, 1);
queue_work(sys->wq, &sys->work);
}
diff --git a/drivers/platform/msm/ipa/ipa_i.h b/drivers/platform/msm/ipa/ipa_i.h
index 3ef300d..5a68dc3 100644
--- a/drivers/platform/msm/ipa/ipa_i.h
+++ b/drivers/platform/msm/ipa/ipa_i.h
@@ -748,6 +748,11 @@
int cnt;
};
+struct ipa_wakelock_ref_cnt {
+ spinlock_t spinlock;
+ int cnt;
+};
+
struct ipa_tag_completion {
struct completion comp;
atomic_t cnt;
@@ -1100,6 +1105,8 @@
* @wcstats: wlan common buffer stats
* @uc_ctx: uC interface context
* @uc_wdi_ctx: WDI specific fields for uC interface
+ * @w_lock: Indicates the wakeup source.
+ * @wakelock_ref_cnt: Indicates the number of times wakelock is acquired
* IPA context - holds all relevant info about IPA driver and its state
*/
@@ -1188,6 +1195,9 @@
struct ipa_uc_wdi_ctx uc_wdi_ctx;
u32 wan_rx_ring_size;
+
+ struct wakeup_source w_lock;
+ struct ipa_wakelock_ref_cnt wakelock_ref_cnt;
};
/**
@@ -1528,4 +1538,6 @@
int ipa_uc_mhi_stop_event_update_channel(int channelHandle);
int ipa_uc_mhi_print_stats(char *dbg_buff, int size);
int ipa_uc_memcpy(phys_addr_t dest, phys_addr_t src, int len);
+void ipa_inc_acquire_wakelock(void);
+void ipa_dec_release_wakelock(void);
#endif /* _IPA_I_H_ */