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
Cette révision appartient à :
Mohit Khanna
2021-11-09 07:47:05 -08:00
révisé par Madan Koyyalamudi
Parent 1b920619fb
révision 49760b669f
4 fichiers modifiés avec 139 ajouts et 67 suppressions

Voir le fichier

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

Voir le fichier

@@ -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;
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;
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 (avg_no_rx_offload_pkts > hdd_ctx->config->bus_bw_high_threshold) {
rxthread_high_tput_req = true;
*is_rx_pm_qos_high = true;
} else {
rxthread_high_tput_req = false;
*is_rx_pm_qos_high = false;
}
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");
}
}

Voir le fichier

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

Voir le fichier

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