Prechádzať zdrojové kódy

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 <[email protected]>
Signed-off-by: Subash Abhinov Kasiviswanathan <[email protected]>
Subash Abhinov Kasiviswanathan 4 rokov pred
rodič
commit
1667d90ff5
2 zmenil súbory, kde vykonal 66 pridanie a 24 odobranie
  1. 63 24
      core/qmi_rmnet.c
  2. 3 0
      core/qmi_rmnet_i.h

+ 63 - 24
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);
 

+ 3 - 0
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 {