Răsfoiți Sursa

qcacld-3.0: Set PM_QOS for non-offloaded TX at V_HIGH

Set system PM_QOS with low latency only for "very-high" throughput levels
in TX case. Currently, its being done for "high" throughput levels.
In less than "very-high" throughput cases, this allows CPU cores to
enter low power modes. This is done only for non-offloaded packets e.g.
UDP.

Change-Id: Idf1dd2968b7dd8b4ef9f4061ee862de03d962c6e
CRs-Fixed: 3045963
Mohit Khanna 3 ani în urmă
părinte
comite
49760b669f

+ 3 - 3
core/hdd/inc/wlan_hdd_main.h

@@ -4991,16 +4991,16 @@ static inline void hdd_beacon_latency_event_cb(uint32_t latency_level)
 #if defined(CLD_PM_QOS) || defined(FEATURE_RUNTIME_PM)
 #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5, 7, 0))
 /**
- * wlan_hdd_get_pm_qos_cpu_latency() - get PM QOS CPU latency
+ * wlan_hdd_get_default_pm_qos_cpu_latency() - get default PM QOS CPU latency
  *
  * Return: PM QOS CPU latency value
  */
-static inline unsigned long wlan_hdd_get_pm_qos_cpu_latency(void)
+static inline unsigned long wlan_hdd_get_default_pm_qos_cpu_latency(void)
 {
 	return PM_QOS_CPU_LATENCY_DEFAULT_VALUE;
 }
 #else
-static inline unsigned long wlan_hdd_get_pm_qos_cpu_latency(void)
+static inline unsigned long wlan_hdd_get_default_pm_qos_cpu_latency(void)
 {
 	return PM_QOS_CPU_DMA_LAT_DEFAULT_VALUE;
 }

+ 101 - 63
core/hdd/src/wlan_hdd_main.c

@@ -9793,20 +9793,22 @@ static void hdd_clear_rps_cpu_mask(struct hdd_context *hdd_ctx)
 /**
  * hdd_pm_qos_update_cpu_mask() - Prepare CPU mask for PM_qos voting
  * @mask: return variable of cpumask for the TPUT
- * @high_throughput: only update high cores mask for high TPUT
+ * @enable_perf_cluster: Enable PERF cluster or not
+ *
+ * By default, the function sets CPU mask for silver cluster unless
+ * enable_perf_cluster is set as true.
  *
  * Return: none
  */
 static inline void hdd_pm_qos_update_cpu_mask(cpumask_t *mask,
-					      bool high_throughput)
+					      bool enable_perf_cluster)
 {
 	cpumask_set_cpu(0, mask);
 	cpumask_set_cpu(1, mask);
 	cpumask_set_cpu(2, mask);
 	cpumask_set_cpu(3, mask);
 
-	if (high_throughput) {
-		/* For high TPUT include GOLD mask also */
+	if (enable_perf_cluster) {
 		cpumask_set_cpu(4, mask);
 		cpumask_set_cpu(5, mask);
 		cpumask_set_cpu(6, mask);
@@ -9823,40 +9825,33 @@ static inline void hdd_pm_qos_update_cpu_mask(cpumask_t *mask,
 #endif
 
 #ifdef CLD_DEV_PM_QOS
-/**
- * hdd_pm_qos_update_request() - API to request for pm_qos
- * @hdd_ctx: handle to hdd context
- * @pm_qos_cpu_mask: cpu_mask to apply
- *
- * Return: none
- */
-static inline void hdd_pm_qos_update_request(struct hdd_context *hdd_ctx,
-					     cpumask_t *pm_qos_cpu_mask)
+
+static inline void _hdd_pm_qos_update_request(struct hdd_context *hdd_ctx,
+					      cpumask_t *pm_qos_cpu_mask,
+					      unsigned int latency)
 {
 	int cpu;
-	unsigned int latency;
+	uint32_t default_latency;
 
+	default_latency = wlan_hdd_get_default_pm_qos_cpu_latency();
 	qdf_cpumask_copy(&hdd_ctx->qos_cpu_mask, pm_qos_cpu_mask);
 
 	if (qdf_cpumask_empty(pm_qos_cpu_mask)) {
-		latency = wlan_hdd_get_pm_qos_cpu_latency();
 		for_each_present_cpu(cpu) {
 			dev_pm_qos_update_request(
 				&hdd_ctx->pm_qos_req[cpu],
-				latency);
+				default_latency);
 		}
 		hdd_debug("Empty mask %*pb: Set latency %u",
 			  qdf_cpumask_pr_args(&hdd_ctx->qos_cpu_mask),
-			  latency);
-	} else {
-		latency = HDD_PM_QOS_HIGH_TPUT_LATENCY_US;
-		/* Set latency to default for CPUs not included in mask */
+			  wlan_hdd_get_default_pm_qos_cpu_latency());
+	} else { /* Set latency to default for CPUs not included in mask */
 		qdf_for_each_cpu_not(cpu, &hdd_ctx->qos_cpu_mask) {
 			dev_pm_qos_update_request(
 				&hdd_ctx->pm_qos_req[cpu],
-				wlan_hdd_get_pm_qos_cpu_latency());
+				default_latency);
 		}
-		/* Set latency to 1 for CPUs included in mask */
+		/* Set latency for CPUs included in mask */
 		qdf_for_each_cpu(cpu, &hdd_ctx->qos_cpu_mask) {
 			dev_pm_qos_update_request(
 				&hdd_ctx->pm_qos_req[cpu],
@@ -9868,20 +9863,41 @@ static inline void hdd_pm_qos_update_request(struct hdd_context *hdd_ctx,
 	}
 }
 
+/**
+ * hdd_pm_qos_update_request() - API to request for pm_qos
+ * @hdd_ctx: handle to hdd context
+ * @pm_qos_cpu_mask: cpu_mask to apply
+ *
+ * Return: none
+ */
+static void hdd_pm_qos_update_request(struct hdd_context *hdd_ctx,
+				      cpumask_t *pm_qos_cpu_mask)
+{
+	unsigned int latency;
+
+	if (qdf_cpumask_empty(pm_qos_cpu_mask))
+		latency = wlan_hdd_get_default_pm_qos_cpu_latency();
+	else
+		latency = HDD_PM_QOS_HIGH_TPUT_LATENCY_US;
+
+	_hdd_pm_qos_update_request(hdd_ctx, pm_qos_cpu_mask, latency);
+}
+
 static inline void hdd_pm_qos_add_request(struct hdd_context *hdd_ctx)
 {
 	struct device *cpu_dev;
 	int cpu;
+	uint32_t default_latency = wlan_hdd_get_default_pm_qos_cpu_latency();
+
 
 	qdf_cpumask_clear(&hdd_ctx->qos_cpu_mask);
 	hdd_pm_qos_update_cpu_mask(&hdd_ctx->qos_cpu_mask, false);
 
 	for_each_present_cpu(cpu) {
 		cpu_dev = get_cpu_device(cpu);
-
 		dev_pm_qos_add_request(cpu_dev, &hdd_ctx->pm_qos_req[cpu],
 				       DEV_PM_QOS_RESUME_LATENCY,
-				       wlan_hdd_get_pm_qos_cpu_latency());
+				       default_latency);
 		hdd_debug("Set qos_cpu_mask %*pb for affine_cores",
 			 cpumask_pr_args(&hdd_ctx->qos_cpu_mask));
 	}
@@ -10070,6 +10086,7 @@ static inline void hdd_low_tput_gro_flush_skip_handler(
  * @hdd_ctx - handle to hdd context
  * @rx_packets - receive packet count in last bus bandwidth interval
  * @next_rx_level - pointer to next_rx_level to be filled
+ * @cpu_mask - pm_qos cpu_mask needed for RX, to be filled
  * @is_rx_pm_qos_high - pointer indicating if high qos is needed, to be filled
  *
  * The function tunes various aspects of the driver based on a running average
@@ -10081,6 +10098,7 @@ static
 bool hdd_bus_bandwidth_work_tune_rx(struct hdd_context *hdd_ctx,
 				    const uint64_t rx_packets,
 				    enum wlan_tp_level *next_rx_level,
+				    cpumask_t *cpu_mask,
 				    bool *is_rx_pm_qos_high)
 {
 	bool rx_level_change = false;
@@ -10107,20 +10125,28 @@ bool hdd_bus_bandwidth_work_tune_rx(struct hdd_context *hdd_ctx,
 	hdd_ctx->prev_rx_offload_pkts = rx_offload_pkts;
 
 	avg_rx = avg_no_rx_offload_pkts + avg_rx_offload_pkts;
-	/*
-	 * Takes care to set Rx_thread affinity for below case
-	 * 1)LRO/GRO not supported ROME case
-	 * 2)when rx_ol is disabled in cases like concurrency etc
-	 * 3)For UDP cases
-	 */
+
+	cpumask_clear(cpu_mask);
+
 	if (avg_no_rx_offload_pkts > hdd_ctx->config->bus_bw_high_threshold) {
 		rxthread_high_tput_req = true;
 		*is_rx_pm_qos_high = true;
-	} else {
+		hdd_pm_qos_update_cpu_mask(cpu_mask, true);
+	} else if (avg_rx > hdd_ctx->config->bus_bw_high_threshold) {
 		rxthread_high_tput_req = false;
 		*is_rx_pm_qos_high = false;
+		hdd_pm_qos_update_cpu_mask(cpu_mask, false);
+	} else {
+		*is_rx_pm_qos_high = false;
+		rxthread_high_tput_req = false;
 	}
 
+	/*
+	 * Takes care to set Rx_thread affinity for below case
+	 * 1)LRO/GRO not supported ROME case
+	 * 2)when rx_ol is disabled in cases like concurrency etc
+	 * 3)For UDP cases
+	 */
 	if (cds_sched_handle_throughput_req(rxthread_high_tput_req))
 		hdd_warn("Rx thread high_tput(%d) affinity request failed",
 			 rxthread_high_tput_req);
@@ -10164,6 +10190,7 @@ bool hdd_bus_bandwidth_work_tune_rx(struct hdd_context *hdd_ctx,
  * @hdd_ctx - handle to hdd context
  * @tx_packets - transmit packet count in last bus bandwidth interval
  * @next_tx_level - pointer to next_tx_level to be filled
+ * @cpu_mask - pm_qos cpu_mask needed for TX, to be filled
  * @is_tx_pm_qos_high - pointer indicating if high qos is needed, to be filled
  *
  * The function tunes various aspects of the driver based on a running average
@@ -10175,6 +10202,7 @@ static
 bool hdd_bus_bandwidth_work_tune_tx(struct hdd_context *hdd_ctx,
 				    const uint64_t tx_packets,
 				    enum wlan_tp_level *next_tx_level,
+				    cpumask_t *cpu_mask,
 				    bool *is_tx_pm_qos_high)
 {
 	bool tx_level_change = false;
@@ -10199,11 +10227,18 @@ bool hdd_bus_bandwidth_work_tune_tx(struct hdd_context *hdd_ctx,
 	/* fine-tuning parameters for TX Flows */
 	hdd_ctx->prev_tx = tx_packets;
 
+	cpumask_clear(cpu_mask);
+
 	if (avg_no_tx_offload_pkts >
-		hdd_ctx->config->bus_bw_high_threshold)
+		hdd_ctx->config->bus_bw_very_high_threshold) {
+		hdd_pm_qos_update_cpu_mask(cpu_mask, true);
 		*is_tx_pm_qos_high = true;
-	else
+	} else if (avg_tx > hdd_ctx->config->bus_bw_high_threshold) {
+		hdd_pm_qos_update_cpu_mask(cpu_mask, false);
+		*is_tx_pm_qos_high = false;
+	} else {
 		*is_tx_pm_qos_high = false;
+	}
 
 	if (avg_tx > hdd_ctx->config->tcp_tx_high_tput_thres)
 		*next_tx_level = WLAN_SVC_TP_HIGH;
@@ -10248,7 +10283,7 @@ static void hdd_pld_request_bus_bandwidth(struct hdd_context *hdd_ctx,
 	enum pld_bus_width_type next_vote_level = PLD_BUS_WIDTH_IDLE;
 	static enum wlan_tp_level next_rx_level = WLAN_SVC_TP_NONE;
 	enum wlan_tp_level next_tx_level = WLAN_SVC_TP_NONE;
-	cpumask_t pm_qos_cpu_mask;
+	cpumask_t pm_qos_cpu_mask_tx, pm_qos_cpu_mask_rx, pm_qos_cpu_mask;
 	bool is_rx_pm_qos_high;
 	bool is_tx_pm_qos_high;
 	enum tput_level tput_level;
@@ -10261,8 +10296,6 @@ static void hdd_pld_request_bus_bandwidth(struct hdd_context *hdd_ctx,
 	if (!soc)
 		return;
 
-	cpumask_clear(&pm_qos_cpu_mask);
-
 	if (hdd_ctx->high_bus_bw_request) {
 		next_vote_level = PLD_BUS_WIDTH_VERY_HIGH;
 		tput_level = TPUT_LEVEL_VERY_HIGH;
@@ -10391,25 +10424,39 @@ static void hdd_pld_request_bus_bandwidth(struct hdd_context *hdd_ctx,
 	rx_level_change = hdd_bus_bandwidth_work_tune_rx(hdd_ctx,
 							 rx_packets,
 							 &next_rx_level,
+							 &pm_qos_cpu_mask_rx,
 							 &is_rx_pm_qos_high);
 
 	tx_level_change = hdd_bus_bandwidth_work_tune_tx(hdd_ctx,
 							 tx_packets,
 							 &next_tx_level,
+							 &pm_qos_cpu_mask_tx,
 							 &is_tx_pm_qos_high);
 
-	hdd_pm_qos_update_cpu_mask(&pm_qos_cpu_mask,
-				   is_tx_pm_qos_high | is_rx_pm_qos_high);
-
 	index = hdd_ctx->hdd_txrx_hist_idx;
 	if (vote_level_change || tx_level_change || rx_level_change) {
-		/* Clear all the mask if no silver/gold vote is required */
+		/* Clear mask if BW is not HIGH or more */
 		if (next_vote_level < PLD_BUS_WIDTH_HIGH) {
 			is_rx_pm_qos_high = false;
 			is_tx_pm_qos_high = false;
 			cpumask_clear(&pm_qos_cpu_mask);
+		} else {
+			cpumask_clear(&pm_qos_cpu_mask);
+
+			cpumask_or(&pm_qos_cpu_mask,
+				   &pm_qos_cpu_mask_tx,
+				   &pm_qos_cpu_mask_rx);
+
+			/* Default mask in case throughput is high */
+			if (qdf_cpumask_empty(&pm_qos_cpu_mask))
+				hdd_pm_qos_update_cpu_mask(&pm_qos_cpu_mask,
+							   false);
 		}
 
+		if (!hdd_ctx->pm_qos_request)
+			hdd_pm_qos_update_request(hdd_ctx,
+						  &pm_qos_cpu_mask);
+
 		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].is_rx_pm_qos_high =
@@ -10422,10 +10469,6 @@ static void hdd_pld_request_bus_bandwidth(struct hdd_context *hdd_ctx,
 		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;
-
-
-		if (!hdd_ctx->pm_qos_request)
-			hdd_pm_qos_update_request(hdd_ctx, &pm_qos_cpu_mask);
 	}
 
 	/* Roaming is a high priority job but gets processed in scheduler
@@ -10873,7 +10916,7 @@ void hdd_adapter_feature_update_work_deinit(struct hdd_adapter *adapter)
 	hdd_exit();
 }
 
-static uint8_t *convert_level_to_string(uint32_t level)
+static uint8_t *hdd_tp_level_to_str(uint32_t level)
 {
 	switch (level) {
 	/* initialize the wlan sub system */
@@ -11026,25 +11069,20 @@ void wlan_hdd_display_tx_rx_histogram(struct hdd_context *hdd_ctx)
 	hdd_nofl_debug("[index][timestamp]: interval_rx, interval_tx, bus_bw_level, RX TP Level, TX TP Level, Rx:Tx pm_qos");
 
 	for (i = 0; i < NUM_TX_RX_HISTOGRAM; i++) {
+		struct hdd_tx_rx_histogram *hist;
+
 		/* using hdd_log to avoid printing function name */
-		if (hdd_ctx->hdd_txrx_hist[i].qtime > 0)
-			hdd_nofl_debug("[%3d][%15llu]: %6llu, %6llu, %s, %s, %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].interval_tx,
-				       convert_level_to_string(
-					hdd_ctx->hdd_txrx_hist[i].
-						next_vote_level),
-				       convert_level_to_string(
-					hdd_ctx->hdd_txrx_hist[i].
-						next_rx_level),
-				       convert_level_to_string(
-					hdd_ctx->hdd_txrx_hist[i].
-						next_tx_level),
-				hdd_ctx->hdd_txrx_hist[i].is_rx_pm_qos_high ?
-				"HIGH" : "LOW",
-				hdd_ctx->hdd_txrx_hist[i].is_tx_pm_qos_high ?
-				"HIGH" : "LOW");
+		if (hdd_ctx->hdd_txrx_hist[i].qtime <= 0)
+			continue;
+		hist = &hdd_ctx->hdd_txrx_hist[i];
+		hdd_nofl_debug("[%3d][%15llu]: %6llu, %6llu, %s, %s, %s, %s:%s",
+			       i, hist->qtime, hist->interval_rx,
+			       hist->interval_tx,
+			       pld_level_to_str(hist->next_vote_level),
+			       hdd_tp_level_to_str(hist->next_rx_level),
+			       hdd_tp_level_to_str(hist->next_tx_level),
+			       hist->is_rx_pm_qos_high ? "HIGH" : "LOW",
+			       hist->is_tx_pm_qos_high ? "HIGH" : "LOW");
 	}
 }
 

+ 8 - 0
core/pld/inc/pld_common.h

@@ -1079,6 +1079,14 @@ int pld_thermal_register(struct device *dev, unsigned long state, int mon_id);
  */
 void pld_thermal_unregister(struct device *dev, int mon_id);
 
+/**
+ * pld_level_to_str() - Helper function to convert PLD bandwidth level to str
+ * @level: PLD bus width level
+ *
+ * Return: String corresponding to input "level"
+ */
+uint8_t *pld_level_to_str(uint32_t level);
+
 /**
  * pld_get_thermal_state() - Get the current thermal state from the PLD
  * @dev: The device structure

+ 26 - 0
core/pld/src/pld_common.c

@@ -3210,6 +3210,32 @@ void pld_thermal_unregister(struct device *dev, int mon_id)
 	}
 }
 
+uint8_t *pld_level_to_str(uint32_t level)
+{
+	switch (level) {
+	/* initialize the wlan sub system */
+	case PLD_BUS_WIDTH_NONE:
+		return "NONE";
+	case PLD_BUS_WIDTH_IDLE:
+		return "IDLE";
+	case PLD_BUS_WIDTH_LOW:
+		return "LOW";
+	case PLD_BUS_WIDTH_MEDIUM:
+		return "MEDIUM";
+	case PLD_BUS_WIDTH_HIGH:
+		return "HIGH";
+	case PLD_BUS_WIDTH_VERY_HIGH:
+		return "VERY_HIGH";
+	case PLD_BUS_WIDTH_LOW_LATENCY:
+		return "LOW_LAT";
+	default:
+		if (level > PLD_BUS_WIDTH_VERY_HIGH)
+			return "VERY_HIGH+";
+		else
+			return "INVAL";
+	}
+}
+
 int pld_get_thermal_state(struct device *dev, unsigned long *thermal_state,
 			  int mon_id)
 {