qcacld-3.0: Add a NAPI mode for roaming

Add a new mode with a pair of new NAPI events, NAPI_EVT_USR_SERIAL
and NAPI_EVT_USR_NORMAL, which allows client force NAPI to move all
instances onto the same CPU and peg them there (blacklist); and
to move back to normal mode of operation.

This part implements the HDD portion. Goes with the corresponding
HIF code.

Change-Id: I4c45d18348ef27d8814c5d0321d1fd13c96fff34
CRs-Fixed: 1078976
diff --git a/core/hdd/inc/wlan_hdd_napi.h b/core/hdd/inc/wlan_hdd_napi.h
index 1ad0ef9..3e81ef6 100644
--- a/core/hdd/inc/wlan_hdd_napi.h
+++ b/core/hdd/inc/wlan_hdd_napi.h
@@ -65,6 +65,7 @@
 int hdd_napi_apply_throughput_policy(struct hdd_context_s *hddctx,
 				     uint64_t              tx_packets,
 				     uint64_t              rx_packets);
+int hdd_napi_serialize(int is_on);
 #else /* FEATURE_NAPI and NOT HELIUM */
 static inline int hdd_napi_apply_throughput_policy(struct hdd_context_s *hddctx,
 						   uint64_t tx_packets,
@@ -72,6 +73,10 @@
 {
 	return 0;
 }
+static inline int hdd_napi_serialize(int is_on)
+{
+	return -EINVAL;
+};
 #endif /* HELIUMPLUS */
 
 #else /* ! defined(FEATURE_NAPI) */
diff --git a/core/hdd/src/wlan_hdd_napi.c b/core/hdd/src/wlan_hdd_napi.c
index 3a20bff..3e5766f 100644
--- a/core/hdd/src/wlan_hdd_napi.c
+++ b/core/hdd/src/wlan_hdd_napi.c
@@ -267,6 +267,7 @@
  * Return: 0 : no action taken, or action return code
  *         !0: error, or action error code
  */
+static int napi_tput_policy_delay;
 int hdd_napi_apply_throughput_policy(struct hdd_context_s *hddctx,
 				     uint64_t              tx_packets,
 				     uint64_t              rx_packets)
@@ -279,6 +280,19 @@
 
 	NAPI_DEBUG("-->%s(tx=%lld, rx=%lld)", __func__, tx_packets, rx_packets);
 
+	if (unlikely(napi_tput_policy_delay < 0))
+		napi_tput_policy_delay = 0;
+	if (napi_tput_policy_delay > 0) {
+		NAPI_DEBUG("%s: delaying policy; delay-count=%d",
+			  __func__, napi_tput_policy_delay);
+		napi_tput_policy_delay--;
+
+		/* make sure the next timer call calls us */
+		hddctx->cur_vote_level = -1;
+
+		return rc;
+	}
+
 	if ((napid != NULL) &&
 	    (enabled = hdd_napi_enabled(HDD_NAPI_ANY))) {
 		if (packets > hddctx->config->busBandwidthHighThreshold)
@@ -295,7 +309,47 @@
 	}
 	return rc;
 }
-#endif
+
+/**
+ * hdd_napi_serialize() - serialize all NAPI activities
+ * @is_on: 1="serialize" or 0="de-serialize"
+ *
+ * Start/stop "serial-NAPI-mode".
+ * NAPI serial mode describes a state where all NAPI operations are forced to be
+ * run serially. This is achieved by ensuring all NAPI instances are run on the
+ * same CPU, so forced to be serial.
+ * NAPI life-cycle:
+ * - Interrupt is received for a given CE.
+ * - In the ISR, the interrupt is masked and corresponding NAPI instance
+ *   is scheduled, to be run as a bottom-half.
+ * - Bottom-half starts with a poll call (by the net_rx softirq). There may be
+ *   one of more subsequent calls until the work is complete.
+ * - Once the work is complete, the poll handler enables the interrupt and
+ *   the cycle re-starts.
+ *
+ * Return: <0: error-code (operation failed)
+ *         =0: success
+ *         >0: status (not used)
+ */
+int hdd_napi_serialize(int is_on)
+{
+	int rc;
+	hdd_context_t *hdd_ctx;
+#define POLICY_DELAY_FACTOR (1)
+	rc = hif_napi_serialize(cds_get_context(QDF_MODULE_ID_HIF), is_on);
+	if ((rc == 0) && (is_on == 0)) {
+		/* apply throughput policy after one timeout */
+		napi_tput_policy_delay = POLICY_DELAY_FACTOR;
+
+		/* make sure that bus_bandwidth trigger is executed */
+		hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
+		if (hdd_ctx != NULL)
+			hdd_ctx->cur_vote_level = -1;
+
+	}
+	return rc;
+}
+#endif /* HELIUMPLUS */
 
 /**
  * hdd_napi_poll() - NAPI poll function