diff options
author | Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> | 2021-05-28 20:29:40 -0700 |
---|---|---|
committer | Subash Abhinov Kasiviswanathan <subashab@codeaurora.org> | 2021-07-07 19:25:46 -0700 |
commit | 1667d90ff51d06207ac82a4ace78572c5429e517 (patch) | |
tree | eb6bce180ef595a7d209b4ace8a3b5fd52583bd6 | |
parent | 3bbb9ff4aeb91ddb57ab9ceab7594c0834baa3fa (diff) | |
download | datarmnet-1667d90ff51d06207ac82a4ace78572c5429e517.tar.gz |
dfc: hold wakelock while powersave timer is running
Powersave alarm timer could fail and delay suspend for 2 seconds
if the timer expires in 2 seconds. Change to hold a wakelock for
the actual duration of the timer so the suspend can be triggered
after timer expiration without delay.
Change-Id: Icc3cb835d4e174955e128c5a0c80198513213b2d
Acked-by: Weiyi Chen <weiyic@qti.qualcomm.com>
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
-rw-r--r-- | core/qmi_rmnet.c | 87 | ||||
-rw-r--r-- | core/qmi_rmnet_i.h | 3 |
2 files changed, 66 insertions, 24 deletions
diff --git a/core/qmi_rmnet.c b/core/qmi_rmnet.c index a1875de..9aaf0c4 100644 --- a/core/qmi_rmnet.c +++ b/core/qmi_rmnet.c @@ -54,10 +54,12 @@ int dfc_ps_ext; unsigned int rmnet_wq_frequency __read_mostly = 1000; #define PS_WORK_ACTIVE_BIT 0 -#define PS_INTERVAL (((!rmnet_wq_frequency) ? \ - 1 : rmnet_wq_frequency/10) * (HZ/100)) + #define NO_DELAY (0x0000 * HZ) -#define PS_INTERVAL_KT (ms_to_ktime(1000)) +#define PS_INTERVAL_MS (rmnet_wq_frequency) +#define PS_INTERVAL_KT (ms_to_ktime(PS_INTERVAL_MS)) +#define PS_INTERVAL_JF (msecs_to_jiffies(PS_INTERVAL_MS)) + #define WATCHDOG_EXPIRE_JF (msecs_to_jiffies(50)) #ifdef CONFIG_QTI_QMI_DFC @@ -632,6 +634,7 @@ qmi_rmnet_setup_client(void *port, struct qmi_info *qmi, struct tcmsg *tcm) if (!qmi) return -ENOMEM; + qmi->ws = wakeup_source_register(NULL, "RMNET_DFC"); rmnet_init_qmi_pt(port, qmi); } @@ -681,6 +684,7 @@ __qmi_rmnet_delete_client(void *port, struct qmi_info *qmi, int idx) if (!qmi_rmnet_has_client(qmi) && !qmi_rmnet_has_pending(qmi)) { rmnet_reset_qmi_pt(port); + wakeup_source_unregister(qmi->ws); kfree(qmi); return 0; } @@ -753,6 +757,7 @@ int qmi_rmnet_change_link(struct net_device *dev, void *port, void *tcm_pt, !qmi_rmnet_has_client(qmi) && !qmi_rmnet_has_pending(qmi)) { rmnet_reset_qmi_pt(port); + wakeup_source_unregister(qmi->ws); kfree(qmi); } @@ -786,7 +791,10 @@ int qmi_rmnet_change_link(struct net_device *dev, void *port, void *tcm_pt, qmi_rmnet_scale_factor = tcm->tcm_ifindex; break; case NLMSG_WQ_FREQUENCY: - rmnet_wq_frequency = tcm->tcm_ifindex; + if (tcm->tcm_ifindex >= 100) + rmnet_wq_frequency = tcm->tcm_ifindex; + else + rc = -EINVAL; break; case NLMSG_CHANNEL_SWITCH: if (!qmi || !DFC_SUPPORTED_MODE(dfc_mode) || @@ -1269,6 +1277,22 @@ static enum alarmtimer_restart qmi_rmnet_work_alarm(struct alarm *atimer, return ALARMTIMER_NORESTART; } +static void dfc_wakelock_acquire(struct qmi_info *qmi) +{ + if (qmi && !qmi->wakelock_active) { + __pm_stay_awake(qmi->ws); + qmi->wakelock_active = true; + } +} + +static void dfc_wakelock_release(struct qmi_info *qmi) +{ + if (qmi && qmi->wakelock_active) { + __pm_relax(qmi->ws); + qmi->wakelock_active = false; + } +} + static void qmi_rmnet_check_stats(struct work_struct *work) { struct rmnet_powersave_work *real_work; @@ -1288,6 +1312,17 @@ static void qmi_rmnet_check_stats(struct work_struct *work) if (unlikely(!qmi)) return; + dfc_wakelock_release(qmi); + + rmnet_get_packets(real_work->port, &rx, &tx); + rxd = rx - real_work->old_rx_pkts; + txd = tx - real_work->old_tx_pkts; + real_work->old_rx_pkts = rx; + real_work->old_tx_pkts = tx; + + dl_msg_active = qmi->dl_msg_active; + qmi->dl_msg_active = false; + if (qmi->ps_enabled) { /* Ready to accept grant */ @@ -1308,15 +1343,6 @@ static void qmi_rmnet_check_stats(struct work_struct *work) goto end; } - rmnet_get_packets(real_work->port, &rx, &tx); - rxd = rx - real_work->old_rx_pkts; - txd = tx - real_work->old_tx_pkts; - real_work->old_rx_pkts = rx; - real_work->old_tx_pkts = tx; - - dl_msg_active = qmi->dl_msg_active; - qmi->dl_msg_active = false; - if (!rxd && !txd) { /* If no DL msg received and there is a flow disabled, * (likely in RLF), no need to enter powersave @@ -1350,12 +1376,19 @@ static void qmi_rmnet_check_stats(struct work_struct *work) end: rcu_read_lock(); if (!rmnet_work_quit) { - if (use_alarm_timer) + if (use_alarm_timer) { + /* Suspend will fail and get delayed for 2s if + * alarmtimer expires within 2s. Hold a wakelock + * for the actual timer duration to prevent suspend + */ + if (PS_INTERVAL_MS < 2000) + dfc_wakelock_acquire(qmi); alarm_start_relative(&real_work->atimer, PS_INTERVAL_KT); - else + } else { queue_delayed_work(rmnet_ps_wq, &real_work->work, - PS_INTERVAL); + PS_INTERVAL_JF); + } } rcu_read_unlock(); } @@ -1378,6 +1411,15 @@ static void qmi_rmnet_check_stats_2(struct work_struct *work) if (unlikely(!qmi)) return; + if (PS_INTERVAL_MS < 2000) + dfc_wakelock_acquire(qmi); + + rmnet_get_packets(real_work->port, &rx, &tx); + rxd = rx - real_work->old_rx_pkts; + txd = tx - real_work->old_tx_pkts; + real_work->old_rx_pkts = rx; + real_work->old_tx_pkts = tx; + if (qmi->ps_enabled) { /* Ready to accept grant */ @@ -1395,12 +1437,6 @@ static void qmi_rmnet_check_stats_2(struct work_struct *work) goto end; } - rmnet_get_packets(real_work->port, &rx, &tx); - rxd = rx - real_work->old_rx_pkts; - txd = tx - real_work->old_tx_pkts; - real_work->old_rx_pkts = rx; - real_work->old_tx_pkts = tx; - if (!rxd && !txd) { rmnet_lock_unlock_all_flows(real_work->port, true); @@ -1425,13 +1461,15 @@ static void qmi_rmnet_check_stats_2(struct work_struct *work) if (rmnet_get_powersave_notif(real_work->port)) qmi_rmnet_ps_on_notify(real_work->port); + dfc_wakelock_release(qmi); return; } end: rcu_read_lock(); - if (!rmnet_work_quit) { + if (!rmnet_work_quit) alarm_start_relative(&real_work->atimer, PS_INTERVAL_KT); - } + else + dfc_wakelock_release(qmi); rcu_read_unlock(); } @@ -1515,6 +1553,7 @@ void qmi_rmnet_work_exit(void *port) rmnet_ps_wq = NULL; kfree(rmnet_work); rmnet_work = NULL; + dfc_wakelock_release((struct qmi_info *)rmnet_get_qmi_pt(port)); } EXPORT_SYMBOL(qmi_rmnet_work_exit); diff --git a/core/qmi_rmnet_i.h b/core/qmi_rmnet_i.h index 0e84138..77759c3 100644 --- a/core/qmi_rmnet_i.h +++ b/core/qmi_rmnet_i.h @@ -17,6 +17,7 @@ #include <linux/netdevice.h> #include <linux/skbuff.h> #include <linux/timer.h> +#include <linux/pm_wakeup.h> #include <uapi/linux/rtnetlink.h> #include <linux/soc/qcom/qmi.h> @@ -140,6 +141,8 @@ struct qmi_info { bool dl_msg_active; bool ps_ignore_grant; int ps_ext; + bool wakelock_active; + struct wakeup_source *ws; }; enum data_ep_type_enum_v01 { |