|
@@ -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);
|
|
|
|