Browse Source

qcacld-3.0: Make interrupt blacklisting robust

Interrupt blacklisting in kernel 4.4 happens through a user-space
entity. The kernel APIs irq_blacklist_on(off) essentially send
a message to the user space service(irq balancer) and
therefore are not synchronous and do not guarantee that blacklisting
has actually taken effect. It will be granted with some latency
(userspace entity's processing delay).

Make blacklisting more robust by:
a) move irq (if it has been moved around after blacklist_on call
   has been made and not yet honored) to the designated CPU
   on IRQ reception
b) stop cpu_isolation in blacklisting mode boost API
c) modify NAPI stats to indicate blacklisting mode

CRs-Fixed: 1093770
Change-Id: I410768d3e0215e510924859d678c66ad7d87b1ec
Mohit Khanna 8 years ago
parent
commit
afff9fb2cf
3 changed files with 42 additions and 32 deletions
  1. 5 6
      core/hdd/inc/wlan_hdd_main.h
  2. 23 23
      core/hdd/src/wlan_hdd_main.c
  3. 14 3
      core/hdd/src/wlan_hdd_napi.c

+ 5 - 6
core/hdd/inc/wlan_hdd_main.h

@@ -330,8 +330,6 @@ extern spinlock_t hdd_context_lock;
  *				received over 100ms intervals
  * @interval_rx:	# of rx packets received in the last 100ms interval
  * @interval_tx:	# of tx packets received in the last 100ms interval
- * @total_rx:		# of total rx packets received on interface
- * @total_tx:		# of total tx packets received on interface
  * @next_vote_level:	pld_bus_width_type voting level (high or low)
  *			determined on the basis of total tx and rx packets
  *			received in the last 100ms interval
@@ -341,18 +339,19 @@ extern spinlock_t hdd_context_lock;
  * @next_tx_level:	pld_bus_width_type voting level (high or low)
  *			determined on the basis of tx packets received in the
  *			last 100ms interval
+ * @qtime		timestamp when the record is added
  *
- * The structure keeps track of throughput requirements of wlan driver in 100ms
- * intervals for later analysis.
+ * The structure keeps track of throughput requirements of wlan driver.
+ * An entry is added if either of next_vote_level, next_rx_level or
+ * next_tx_level changes. An entry is not added for every 100ms interval.
  */
 struct hdd_tx_rx_histogram {
 	uint64_t interval_rx;
 	uint64_t interval_tx;
-	uint64_t total_rx;
-	uint64_t total_tx;
 	uint32_t next_vote_level;
 	uint32_t next_rx_level;
 	uint32_t next_tx_level;
+	uint64_t qtime;
 };
 
 typedef struct hdd_tx_rx_stats_s {

+ 23 - 23
core/hdd/src/wlan_hdd_main.c

@@ -5799,6 +5799,10 @@ static void hdd_pld_request_bus_bandwidth(hdd_context_t *hdd_ctx,
 	enum wlan_tp_level next_rx_level = WLAN_SVC_TP_NONE;
 	enum wlan_tp_level next_tx_level = WLAN_SVC_TP_NONE;
 	uint32_t delack_timer_cnt = hdd_ctx->config->tcp_delack_timer_count;
+	uint16_t index = 0;
+	bool vote_level_change = false;
+	bool rx_level_change = false;
+	bool tx_level_change = false;
 
 	if (total > hdd_ctx->config->busBandwidthHighThreshold)
 		next_vote_level = PLD_BUS_WIDTH_HIGH;
@@ -5809,13 +5813,11 @@ static void hdd_pld_request_bus_bandwidth(hdd_context_t *hdd_ctx,
 	else
 		next_vote_level = PLD_BUS_WIDTH_NONE;
 
-	hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].next_vote_level =
-							next_vote_level;
-
 	if (hdd_ctx->cur_vote_level != next_vote_level) {
 		hdd_debug("trigger level %d, tx_packets: %lld, rx_packets: %lld",
 			 next_vote_level, tx_packets, rx_packets);
 		hdd_ctx->cur_vote_level = next_vote_level;
+		vote_level_change = true;
 		pld_request_bus_bandwidth(hdd_ctx->parent_dev, next_vote_level);
 		if (next_vote_level == PLD_BUS_WIDTH_LOW) {
 			if (hdd_ctx->hbw_requested) {
@@ -5850,13 +5852,11 @@ static void hdd_pld_request_bus_bandwidth(hdd_context_t *hdd_ctx,
 		hdd_ctx->rx_high_ind_cnt = 0;
 	}
 
-	hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].next_rx_level =
-								next_rx_level;
-
 	if (hdd_ctx->cur_rx_level != next_rx_level) {
 		hdd_debug("TCP DELACK trigger level %d, average_rx: %llu",
 		       next_rx_level, temp_rx);
 		hdd_ctx->cur_rx_level = next_rx_level;
+		rx_level_change = true;
 		/* Send throughput indication only if it is enabled.
 		 * Disabling tcp_del_ack will revert the tcp stack behavior
 		 * to default delayed ack. Note that this will disable the
@@ -5881,16 +5881,25 @@ static void hdd_pld_request_bus_bandwidth(hdd_context_t *hdd_ctx,
 		hdd_debug("change TCP TX trigger level %d, average_tx: %llu",
 				next_tx_level, temp_tx);
 		hdd_ctx->cur_tx_level = next_tx_level;
+		tx_level_change = true;
 		wlan_hdd_send_svc_nlink_msg(hdd_ctx->radio_index,
 				WLAN_SVC_WLAN_TP_TX_IND,
 				&next_tx_level,
 				sizeof(next_tx_level));
 	}
 
-	hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].next_tx_level =
-								next_tx_level;
-	hdd_ctx->hdd_txrx_hist_idx++;
-	hdd_ctx->hdd_txrx_hist_idx &= NUM_TX_RX_HISTOGRAM_MASK;
+	index = hdd_ctx->hdd_txrx_hist_idx;
+
+	if (vote_level_change || tx_level_change || rx_level_change) {
+		hdd_ctx->hdd_txrx_hist[index].next_tx_level = next_tx_level;
+		hdd_ctx->hdd_txrx_hist[index].next_rx_level = next_rx_level;
+		hdd_ctx->hdd_txrx_hist[index].next_vote_level = next_vote_level;
+		hdd_ctx->hdd_txrx_hist[index].interval_rx = rx_packets;
+		hdd_ctx->hdd_txrx_hist[index].interval_tx = tx_packets;
+		hdd_ctx->hdd_txrx_hist[index].qtime = qdf_get_log_timestamp();
+		hdd_ctx->hdd_txrx_hist_idx++;
+		hdd_ctx->hdd_txrx_hist_idx &= NUM_TX_RX_HISTOGRAM_MASK;
+	}
 }
 
 #define HDD_BW_GET_DIFF(_x, _y) (unsigned long)((ULONG_MAX - (_y)) + (_x) + 1)
@@ -5977,13 +5986,6 @@ static void hdd_bus_bw_work_handler(struct work_struct *work)
 		connected = true;
 	}
 
-	hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].total_rx = total_rx;
-	hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].total_tx = total_tx;
-	hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].interval_rx =
-								rx_packets;
-	hdd_ctx->hdd_txrx_hist[hdd_ctx->hdd_txrx_hist_idx].interval_tx =
-								tx_packets;
-
 	/* add intra bss forwarded tx and rx packets */
 	tx_packets += fwd_tx_packets_diff;
 	rx_packets += fwd_rx_packets_diff;
@@ -6147,17 +6149,15 @@ void wlan_hdd_display_tx_rx_histogram(hdd_context_t *hdd_ctx)
 	hdd_err("Total entries: %d Current index: %d",
 		NUM_TX_RX_HISTOGRAM, hdd_ctx->hdd_txrx_hist_idx);
 
-	hdd_err("index, total_rx, interval_rx, total_tx, interval_tx, bus_bw_level, RX TP Level, TX TP Level");
+	hdd_err("[index][timestamp]: interval_rx, interval_tx, bus_bw_level, RX TP Level, TX TP Level");
 
 	for (i = 0; i < NUM_TX_RX_HISTOGRAM; i++) {
 		/* using hdd_log to avoid printing function name */
-		if (hdd_ctx->hdd_txrx_hist[i].total_rx != 0 ||
-			hdd_ctx->hdd_txrx_hist[i].total_tx != 0)
+		if (hdd_ctx->hdd_txrx_hist[i].qtime > 0)
 			hdd_log(QDF_TRACE_LEVEL_ERROR,
-				"%d: %llu, %llu, %llu, %llu, %s, %s, %s",
-				i, hdd_ctx->hdd_txrx_hist[i].total_rx,
+				"[%3d][%15llu]: %6llu, %6llu, %s, %s, %s",
+				i, hdd_ctx->hdd_txrx_hist[i].qtime,
 				hdd_ctx->hdd_txrx_hist[i].interval_rx,
-				hdd_ctx->hdd_txrx_hist[i].total_tx,
 				hdd_ctx->hdd_txrx_hist[i].interval_tx,
 				convert_level_to_string(
 					hdd_ctx->hdd_txrx_hist[i].

+ 14 - 3
core/hdd/src/wlan_hdd_napi.c

@@ -106,6 +106,7 @@ int hdd_napi_create(void)
 	struct  hif_opaque_softc *hif_ctx;
 	int     rc = 0;
 	hdd_context_t *hdd_ctx;
+	uint8_t feature_flags = 0;
 
 	NAPI_DEBUG("-->");
 
@@ -114,9 +115,15 @@ int hdd_napi_create(void)
 		QDF_ASSERT(NULL != hif_ctx);
 		rc = -EFAULT;
 	} else {
+
+		feature_flags = QCA_NAPI_FEATURE_CPU_CORRECTION |
+				QCA_NAPI_FEATURE_IRQ_BLACKLISTING |
+				QCA_NAPI_FEATURE_CORE_CTL_BOOST;
+
 		rc = hif_napi_create(hif_ctx, hdd_napi_poll,
 				     QCA_NAPI_BUDGET,
-				     QCA_NAPI_DEF_SCALE);
+				     QCA_NAPI_DEF_SCALE,
+				     feature_flags);
 		if (rc < 0) {
 			hdd_err("ERR(%d) creating NAPI instances",
 				rc);
@@ -399,7 +406,10 @@ int hdd_display_napi_stats(void)
 		hdd_err("%s unable to retrieve napi structure", __func__);
 		return -EFAULT;
 	}
-	qdf_print("[NAPI -- STATS]:  scheds   polls   comps    done time-lim pkt-lim napi-buckets(%d)", QCA_NAPI_NUM_BUCKETS);
+	qdf_print("[NAPI %u][BL %d]:  scheds   polls   comps    done t-lim p-lim  corr napi-buckets(%d)",
+		  napid->napi_mode,
+		  hif_napi_cpu_blacklist(napid->flags, BLACKLIST_QUERY),
+		  QCA_NAPI_NUM_BUCKETS);
 
 	for (i = 0; i < CE_COUNT_MAX; i++)
 		if (napid->ce_map & (0x01 << i)) {
@@ -416,7 +426,7 @@ int hdd_display_napi_stats(void)
 				}
 
 				if (napis->napi_schedules != 0)
-					qdf_print("NAPI[%2d]CPU[%2d]: %7d %7d %7d %7d %8d %7d %s",
+					qdf_print("NAPI[%2d]CPU[%d]: %7d %7d %7d %7d %5d %5d %5d %s",
 						  i, j,
 						  napis->napi_schedules,
 						  napis->napi_polls,
@@ -424,6 +434,7 @@ int hdd_display_napi_stats(void)
 						  napis->napi_workdone,
 						  napis->time_limit_reached,
 						  napis->rxpkt_thresh_reached,
+						  napis->cpu_corrected,
 						  buf);
 			}
 		}