qcacld-3.0: Add support to get thermal throttle stats

Add support for sending WMI_REQUEST_THERMAL_STATS_CMDID
to request for the thermal stats via vendor cmd:
QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_THERMAL_STATS
This vendor cmd can either be used to clear the thermal
stats or to request for the thermal stats.
Added ini gThermalStatsTempOffset, which can
configure thermal temperature offset value for capturing
thermal stats in  thermal range such as Thermal STATS
starts capturing from temperature threshold to temperature
threshold + offset.
If this ini is set to 0, then the events are disabled.
Also, add support for the FW event where the requested
thermal stats are sent in FW event
WMI_THERM_THROT_STATS_EVENTID().
The following attributes are sent in the events for every
level:
	STATS_MIN_TEMPERATURE
	STATS_MAX_TEMPERATURE
	STATS_DWELL_TIME
	STATS_TEMP_LEVEL_COUNTER

Change-Id: If8acdeec5bde33be346332ccaf39d78d0151203d
CRs-Fixed: 3016818
This commit is contained in:
Utkarsh Bhatnagar 2021-09-17 11:46:16 +05:30 • committed by Gerrit - the friendly Code Review server
commit 1fba4f1b08
17 changed files with 879 additions and 22 deletions

1
Kbuild
View file

@ -2603,6 +2603,7 @@ cppflags-y += -DANI_OS_TYPE_ANDROID=6 \
-Werror\
-D__linux__
cppflags-$(CONFIG_THERMAL_STATS_SUPPORT) += -DTHERMAL_STATS_SUPPORT
cppflags-$(CONFIG_PTT_SOCK_SVC_ENABLE) += -DPTT_SOCK_SVC_ENABLE
cppflags-$(CONFIG_FEATURE_WLAN_WAPI) += -DFEATURE_WLAN_WAPI
cppflags-$(CONFIG_FEATURE_WLAN_WAPI) += -DATH_SUPPORT_WAPI

View file

@ -51,10 +51,12 @@
/**
* enum wlan_fwol_southbound_event - fw offload south bound event type
* @WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE: get eLNA bypass response
* @WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE: get Thermal Stats response
*/
enum wlan_fwol_southbound_event {
WLAN_FWOL_EVT_INVALID = 0,
WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE,
WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE,
WLAN_FWOL_EVT_LAST,
WLAN_FWOL_EVT_MAX = WLAN_FWOL_EVT_LAST - 1
};
@ -116,6 +118,7 @@ struct wlan_fwol_coex_config {
* @priority_apps: Priority of the apps mitigation to consider by fw
* @priority_wpps: Priority of the wpps mitigation to consider by fw
* @thermal_action: thermal action as defined enum thermal_mgmt_action_code
* @therm_stats_offset: thermal temp offset as set in gThermalStatsTempOffset
*/
struct wlan_fwol_thermal_temp {
bool thermal_mitigation_enable;
@ -128,6 +131,9 @@ struct wlan_fwol_thermal_temp {
uint8_t priority_apps;
uint8_t priority_wpps;
enum thermal_mgmt_action_code thermal_action;
#ifdef THERMAL_STATS_SUPPORT
uint8_t therm_stats_offset;
#endif
};
/**
@ -275,18 +281,30 @@ struct wlan_fwol_cfg {
bool disable_hw_assist;
};
/**
* struct wlan_fwol_capability_info - FW offload capability component
* @fw_thermal_stats_cap: Thermal Stats Fw capability
**/
struct wlan_fwol_capability_info {
#ifdef THERMAL_STATS_SUPPORT
bool fw_thermal_stats_cap;
#endif
};
/**
* struct wlan_fwol_psoc_obj - FW offload psoc priv object
* @cfg: cfg items
* @cbs: callback functions
* @tx_ops: tx operations for target interface
* @rx_ops: rx operations for target interface
* @capability_info: fwol capability info
*/
struct wlan_fwol_psoc_obj {
struct wlan_fwol_cfg cfg;
struct wlan_fwol_callbacks cbs;
struct wlan_fwol_tx_ops tx_ops;
struct wlan_fwol_rx_ops rx_ops;
struct wlan_fwol_capability_info capability_info;
};
/**
@ -294,6 +312,7 @@ struct wlan_fwol_psoc_obj {
* @psoc: psoc handle
* @event_id: event ID
* @get_elna_bypass_response: get eLNA bypass response
* @get_thermal_stats_response: get thermal stats response
*/
struct wlan_fwol_rx_event {
struct wlan_objmgr_psoc *psoc;
@ -301,6 +320,9 @@ struct wlan_fwol_rx_event {
union {
#ifdef WLAN_FEATURE_ELNA
struct get_elna_bypass_response get_elna_bypass_response;
#endif
#ifdef THERMAL_STATS_SUPPORT
struct thermal_throttle_info get_thermal_stats_response;
#endif
};
};

View file

@ -111,6 +111,22 @@ fwol_init_coex_config_in_cfg(struct wlan_objmgr_psoc *psoc,
CFG_BLE_SCAN_COEX_POLICY);
}
#ifdef THERMAL_STATS_SUPPORT
static void
fwol_init_thermal_stats_in_cfg(struct wlan_objmgr_psoc *psoc,
struct wlan_fwol_thermal_temp *thermal_temp)
{
thermal_temp->therm_stats_offset =
cfg_get(psoc, CFG_THERMAL_STATS_TEMP_OFFSET);
}
#else
static void
fwol_init_thermal_stats_in_cfg(struct wlan_objmgr_psoc *psoc,
struct wlan_fwol_thermal_temp *thermal_temp)
{
}
#endif
static void
fwol_init_thermal_temp_in_cfg(struct wlan_objmgr_psoc *psoc,
struct wlan_fwol_thermal_temp *thermal_temp)
@ -155,7 +171,7 @@ fwol_init_thermal_temp_in_cfg(struct wlan_objmgr_psoc *psoc,
cfg_get(psoc, CFG_THERMAL_WPPS_PRIOITY);
thermal_temp->thermal_action =
cfg_get(psoc, CFG_THERMAL_MGMT_ACTION);
fwol_init_thermal_stats_in_cfg(psoc, thermal_temp);
}
QDF_STATUS fwol_init_neighbor_report_cfg(struct wlan_objmgr_psoc *psoc,
@ -622,6 +638,59 @@ fwol_process_get_elna_bypass_resp(struct wlan_fwol_rx_event *event)
}
#endif /* WLAN_FEATURE_ELNA */
#ifdef THERMAL_STATS_SUPPORT
/**
* fwol_process_get_thermal_stats_resp() - Process get thermal stats response
* @event: response event
*
* Return: QDF_STATUS_SUCCESS on success
*/
static QDF_STATUS
fwol_process_get_thermal_stats_resp(struct wlan_fwol_rx_event *event)
{
QDF_STATUS status = QDF_STATUS_SUCCESS;
struct wlan_objmgr_psoc *psoc;
struct wlan_fwol_psoc_obj *fwol_obj;
struct wlan_fwol_callbacks *cbs;
struct thermal_throttle_info *resp;
if (!event) {
fwol_err("Event buffer is NULL");
return QDF_STATUS_E_FAILURE;
}
psoc = event->psoc;
if (!psoc) {
fwol_err("psoc is NULL");
return QDF_STATUS_E_INVAL;
}
fwol_obj = fwol_get_psoc_obj(psoc);
if (!fwol_obj) {
fwol_err("Failed to get FWOL Obj");
return QDF_STATUS_E_INVAL;
}
cbs = &fwol_obj->cbs;
if (cbs && cbs->get_thermal_stats_callback) {
resp = &event->get_thermal_stats_response;
cbs->get_thermal_stats_callback(cbs->get_thermal_stats_context,
resp);
} else {
fwol_err("NULL pointer for callback");
status = QDF_STATUS_E_IO;
}
return status;
}
#else
static QDF_STATUS
fwol_process_get_thermal_stats_resp(struct wlan_fwol_rx_event *event)
{
return QDF_STATUS_E_NOSUPPORT;
}
#endif /* THERMAL_STATS_SUPPORT */
QDF_STATUS fwol_process_event(struct scheduler_msg *msg)
{
QDF_STATUS status;
@ -641,6 +710,9 @@ QDF_STATUS fwol_process_event(struct scheduler_msg *msg)
case WLAN_FWOL_EVT_GET_ELNA_BYPASS_RESPONSE:
status = fwol_process_get_elna_bypass_resp(event);
break;
case WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE:
status = fwol_process_get_thermal_stats_resp(event);
break;
default:
status = QDF_STATUS_E_INVAL;
break;

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012-2018,2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2012-2018,2020-2021 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@ -430,6 +430,31 @@
CFG_VALUE_OR_DEFAULT, \
"Thermal management action")
/* <ini>
* gThermalStatsTempOffset - Configure the thermal stats offset
*
* @Min: 0
* @Max: 10
* @Default: 5
*
* This ini will configure Thermal temperature offset value for capturing
* thermal stats in thermal range.
* Thermal STATS start capturing from temperature threshold to temperature
* threshold + offset.
* If the value 0 is given then then thermal STATS capture is disabled
*
* Usage: External
*
* </ini>
*/
#define CFG_THERMAL_STATS_TEMP_OFFSET CFG_INI_UINT( \
"gThermalStatsTempOffset", \
0, \
10, \
5, \
CFG_VALUE_OR_DEFAULT, \
"Thermal Stats Temperature Offset")
#define CFG_THERMAL_TEMP_ALL \
CFG(CFG_THERMAL_TEMP_MIN_LEVEL0) \
CFG(CFG_THERMAL_TEMP_MAX_LEVEL0) \
@ -450,6 +475,7 @@
CFG(CFG_THERMAL_SAMPLING_TIME) \
CFG(CFG_THERMAL_APPS_PRIORITY) \
CFG(CFG_THERMAL_WPPS_PRIOITY) \
CFG(CFG_THERMAL_MGMT_ACTION)
CFG(CFG_THERMAL_MGMT_ACTION) \
CFG(CFG_THERMAL_STATS_TEMP_OFFSET)
#endif

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@ -24,6 +24,8 @@
#define _WLAN_FWOL_PUBLIC_STRUCTS_H_
#include "wlan_objmgr_psoc_obj.h"
#include "wlan_thermal_public_struct.h"
#include "wmi_unified.h"
#ifdef WLAN_FEATURE_ELNA
/**
@ -57,10 +59,28 @@ struct get_elna_bypass_response {
};
#endif
/**
* struct thermal_throttle_info - thermal throttle info from Target
* @temperature: current temperature in c Degree
* @level: target thermal level info
* @pdev_id: pdev id
* @therm_throt_levels: Number of thermal throttle levels
* @level_info: Thermal Stats for each level
*/
struct thermal_throttle_info {
uint32_t temperature;
enum thermal_throttle_level level;
uint32_t pdev_id;
uint32_t therm_throt_levels;
struct thermal_throt_level_stats level_info[WMI_THERMAL_STATS_TEMP_THRESH_LEVEL_MAX];
};
/**
* struct wlan_fwol_callbacks - fw offload callbacks
* @get_elna_bypass_callback: callback for get eLNA bypass
* @get_elna_bypass_context: context for get eLNA bypass
* @get_thermal_stats_callback: callback for get thermal stats
* @get_thermal_stats_context: context for get thermal stats
*/
struct wlan_fwol_callbacks {
#ifdef WLAN_FEATURE_ELNA
@ -68,6 +88,11 @@ struct wlan_fwol_callbacks {
struct get_elna_bypass_response *response);
void *get_elna_bypass_context;
#endif
#ifdef THERMAL_STATS_SUPPORT
void (*get_thermal_stats_callback)(void *context,
struct thermal_throttle_info *response);
void *get_thermal_stats_context;
#endif
};
/**
@ -77,6 +102,7 @@ struct wlan_fwol_callbacks {
* @reg_evt_handler: register event handler
* @unreg_evt_handler: unregister event handler
* @send_dscp_up_map_to_fw: send dscp-to-up map values to FW
* @get_thermal_stats: send get_thermal_stats cmd to FW
*/
struct wlan_fwol_tx_ops {
#ifdef WLAN_FEATURE_ELNA
@ -94,17 +120,27 @@ struct wlan_fwol_tx_ops {
struct wlan_objmgr_psoc *psoc,
uint32_t *dscp_to_up_map);
#endif
#ifdef THERMAL_STATS_SUPPORT
QDF_STATUS (*get_thermal_stats)(struct wlan_objmgr_psoc *psoc,
enum thermal_stats_request_type req_type,
uint8_t therm_stats_offset);
#endif
};
/**
* struct wlan_fwol_rx_ops - structure of rx func pointers
* @get_elna_bypass_resp: get eLNA bypass response
* @get_thermal_stats_resp: thermal stats cmd response callback to fwol
*/
struct wlan_fwol_rx_ops {
#ifdef WLAN_FEATURE_ELNA
QDF_STATUS (*get_elna_bypass_resp)(struct wlan_objmgr_psoc *psoc,
struct get_elna_bypass_response *resp);
#endif
#ifdef THERMAL_STATS_SUPPORT
QDF_STATUS (*get_thermal_stats_resp)(struct wlan_objmgr_psoc *psoc,
struct thermal_throttle_info *resp);
#endif
};
#endif /* _WLAN_FWOL_PUBLIC_STRUCTS_H_ */

View file

@ -608,6 +608,26 @@ QDF_STATUS ucfg_fwol_send_dscp_up_map_to_fw(
}
#endif
/**
* ucfg_fwol_update_fw_cap_info - API to update fwol capability info
* @psoc: pointer to psoc object
* @caps: pointer to wlan_fwol_capability_info struct
*
* Used to update fwol capability info.
*
* Return: void
*/
void ucfg_fwol_update_fw_cap_info(struct wlan_objmgr_psoc *psoc,
struct wlan_fwol_capability_info *caps);
#ifdef THERMAL_STATS_SUPPORT
QDF_STATUS ucfg_fwol_send_get_thermal_stats_cmd(struct wlan_objmgr_psoc *psoc,
enum thermal_stats_request_type req_type,
void (*callback)(void *context,
struct thermal_throttle_info *response),
void *context);
#endif /* THERMAL_STATS_SUPPORT */
/**
* ucfg_fwol_configure_global_params - API to configure global params
* @psoc: pointer to psoc object

View file

@ -166,9 +166,67 @@ static void tgt_fwol_register_elna_rx_ops(struct wlan_fwol_rx_ops *rx_ops)
}
#endif /* WLAN_FEATURE_ELNA */
#ifdef THERMAL_STATS_SUPPORT
static QDF_STATUS
tgt_fwol_get_thermal_stats_resp(struct wlan_objmgr_psoc *psoc,
struct thermal_throttle_info *resp)
{
QDF_STATUS status;
struct scheduler_msg msg = {0};
struct wlan_fwol_rx_event *event;
event = qdf_mem_malloc(sizeof(*event));
if (!event)
return QDF_STATUS_E_NOMEM;
status = wlan_objmgr_psoc_try_get_ref(psoc, WLAN_FWOL_SB_ID);
if (QDF_IS_STATUS_ERROR(status)) {
fwol_err("Failed to get psoc ref");
fwol_release_rx_event(event);
return status;
}
event->psoc = psoc;
event->event_id = WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE;
event->get_thermal_stats_response = *resp;
msg.type = WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE;
msg.bodyptr = event;
msg.callback = fwol_process_event;
msg.flush_callback = fwol_flush_callback;
status = scheduler_post_message(QDF_MODULE_ID_FWOL,
QDF_MODULE_ID_FWOL,
QDF_MODULE_ID_TARGET_IF, &msg);
if (QDF_IS_STATUS_SUCCESS(status))
return QDF_STATUS_SUCCESS;
fwol_err("failed to send WLAN_FWOL_EVT_GET_THERMAL_STATS_RESPONSE msg");
fwol_flush_callback(&msg);
return status;
}
static void
tgt_fwol_register_thermal_stats_resp(struct wlan_fwol_rx_ops *rx_ops)
{
rx_ops->get_thermal_stats_resp = tgt_fwol_get_thermal_stats_resp;
}
#else
static void
tgt_fwol_register_thermal_stats_resp(struct wlan_fwol_rx_ops *rx_ops)
{
}
#endif
static void tgt_fwol_register_thermal_rx_ops(struct wlan_fwol_rx_ops *rx_ops)
{
tgt_fwol_register_thermal_stats_resp(rx_ops);
}
QDF_STATUS tgt_fwol_register_rx_ops(struct wlan_fwol_rx_ops *rx_ops)
{
tgt_fwol_register_elna_rx_ops(rx_ops);
tgt_fwol_register_thermal_rx_ops(rx_ops);
return QDF_STATUS_SUCCESS;
}

View file

@ -1001,6 +1001,96 @@ QDF_STATUS ucfg_fwol_send_dscp_up_map_to_fw(struct wlan_objmgr_vdev *vdev,
}
#endif /* WLAN_SEND_DSCP_UP_MAP_TO_FW */
void ucfg_fwol_update_fw_cap_info(struct wlan_objmgr_psoc *psoc,
struct wlan_fwol_capability_info *caps)
{
struct wlan_fwol_psoc_obj *fwol_obj;
fwol_obj = fwol_get_psoc_obj(psoc);
if (!fwol_obj) {
fwol_err("Failed to get fwol obj");
return;
}
qdf_mem_copy(&fwol_obj->capability_info, caps,
sizeof(fwol_obj->capability_info));
}
#ifdef THERMAL_STATS_SUPPORT
static QDF_STATUS
ucfg_fwol_get_cap(struct wlan_objmgr_psoc *psoc,
struct wlan_fwol_capability_info *cap_info)
{
struct wlan_fwol_psoc_obj *fwol_obj;
fwol_obj = fwol_get_psoc_obj(psoc);
if (!fwol_obj) {
fwol_err("Failed to get fwol obj");
return QDF_STATUS_E_FAILURE;
}
if (!cap_info) {
fwol_err("Failed to get fwol obj");
return QDF_STATUS_E_FAILURE;
}
*cap_info = fwol_obj->capability_info;
return QDF_STATUS_SUCCESS;
}
QDF_STATUS ucfg_fwol_send_get_thermal_stats_cmd(struct wlan_objmgr_psoc *psoc,
enum thermal_stats_request_type req_type,
void (*callback)(void *context,
struct thermal_throttle_info *response),
void *context)
{
QDF_STATUS status;
struct wlan_fwol_psoc_obj *fwol_obj;
struct wlan_fwol_tx_ops *tx_ops;
struct wlan_fwol_thermal_temp thermal_temp = {0};
struct wlan_fwol_capability_info cap_info;
struct wlan_fwol_callbacks *cbs;
fwol_obj = fwol_get_psoc_obj(psoc);
if (!fwol_obj) {
fwol_err("Failed to get FWOL Obj");
return QDF_STATUS_E_INVAL;
}
status = ucfg_fwol_get_thermal_temp(psoc, &thermal_temp);
if (QDF_IS_STATUS_ERROR(status))
return QDF_STATUS_E_INVAL;
status = ucfg_fwol_get_cap(psoc, &cap_info);
if (QDF_IS_STATUS_ERROR(status))
return QDF_STATUS_E_INVAL;
if (!thermal_temp.therm_stats_offset ||
!cap_info.fw_thermal_stats_cap) {
fwol_err("Command Disabled in Ini gThermalStatsTempOffset %d or not enabled in FW %d",
thermal_temp.therm_stats_offset,
cap_info.fw_thermal_stats_cap);
return QDF_STATUS_E_INVAL;
}
/* Registering Callback for the Request command */
if (callback && context) {
cbs = &fwol_obj->cbs;
cbs->get_thermal_stats_callback = callback;
cbs->get_thermal_stats_context = context;
}
tx_ops = &fwol_obj->tx_ops;
if (tx_ops && tx_ops->get_thermal_stats)
status = tx_ops->get_thermal_stats(psoc, req_type,
thermal_temp.therm_stats_offset);
else
status = QDF_STATUS_E_INVAL;
return status;
}
#endif /* THERMAL_STATS_SUPPORT */
QDF_STATUS ucfg_fwol_configure_global_params(struct wlan_objmgr_psoc *psoc,
struct wlan_objmgr_pdev *pdev)
{

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@ -240,10 +240,203 @@ target_if_fwol_register_dscp_up_tx_ops(struct wlan_fwol_tx_ops *tx_ops)
}
#endif
#ifdef THERMAL_STATS_SUPPORT
/**
* target_if_fwol_get_thermal_stats() - send get thermal stats request to FW
* @psoc: pointer to PSOC object
* @req_type: get thermal stats request type
* @therm_stats_offset: thermal temp stats offset for each temp range
*
* Return: QDF_STATUS_SUCCESS on success
*/
static QDF_STATUS
target_if_fwol_get_thermal_stats(struct wlan_objmgr_psoc *psoc,
enum thermal_stats_request_type req_type,
uint8_t therm_stats_offset)
{
QDF_STATUS status;
wmi_unified_t wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
if (!wmi_handle) {
target_if_err("Invalid wmi_handle");
return QDF_STATUS_E_INVAL;
}
status = wmi_unified_send_get_thermal_stats_cmd(wmi_handle, req_type,
therm_stats_offset);
if (status)
target_if_err("Failed to send get thermal stats cmd %d",
status);
return status;
}
static void
target_if_fwol_register_thermal_stats_tx_ops(struct wlan_fwol_tx_ops *tx_ops)
{
tx_ops->get_thermal_stats = target_if_fwol_get_thermal_stats;
}
static QDF_STATUS
target_if_fwol_handle_thermal_lvl_stats_evt(struct wlan_objmgr_psoc *psoc,
struct wlan_fwol_rx_ops *rx_ops,
struct thermal_throttle_info *info)
{
QDF_STATUS status = QDF_STATUS_E_FAILURE;
if (rx_ops->get_thermal_stats_resp && info->therm_throt_levels)
status = rx_ops->get_thermal_stats_resp(psoc, info);
return status;
}
static bool
target_if_fwol_is_thermal_stats_enable(struct wlan_fwol_psoc_obj *fwol_obj)
{
return (fwol_obj->capability_info.fw_thermal_stats_cap &&
fwol_obj->cfg.thermal_temp_cfg.therm_stats_offset);
}
/**
* target_if_fwol_thermal_throttle_event_handler() - handler for thermal
* throttle event
* @scn: scn handle
* @event_buf: pointer to the event buffer
* @len: length of the buffer
*
* Return: 0 on success
*/
static int
target_if_fwol_thermal_throttle_event_handler(ol_scn_t scn, uint8_t *event_buf,
uint32_t len)
{
QDF_STATUS status = QDF_STATUS_E_FAILURE;
struct thermal_throttle_info info = {0};
struct wlan_objmgr_psoc *psoc;
wmi_unified_t wmi_handle;
struct wlan_fwol_psoc_obj *fwol_obj;
struct wlan_fwol_rx_ops *rx_ops;
target_if_debug("scn:%pK, data:%pK, datalen:%d", scn, event_buf, len);
if (!scn || !event_buf)
return -EINVAL;
psoc = target_if_get_psoc_from_scn_hdl(scn);
if (!psoc) {
target_if_err("null psoc");
return -EINVAL;
}
wmi_handle = get_wmi_unified_hdl_from_psoc(psoc);
if (!wmi_handle) {
target_if_err("Invalid wmi_handle");
return -EINVAL;
}
fwol_obj = fwol_get_psoc_obj(psoc);
if (!fwol_obj) {
target_if_err("Failed to get FWOL Obj");
return -EINVAL;
}
status = wmi_extract_thermal_stats(wmi_handle,
event_buf,
&info.temperature,
&info.level,
&info.therm_throt_levels,
info.level_info,
&info.pdev_id);
if (QDF_IS_STATUS_ERROR(status)) {
target_if_debug("Failed to convert thermal target level");
return -EINVAL;
}
rx_ops = &fwol_obj->rx_ops;
if (!rx_ops) {
target_if_debug("rx_ops Null");
return -EINVAL;
}
status = target_if_fwol_handle_thermal_lvl_stats_evt(psoc, rx_ops,
&info);
if (QDF_IS_STATUS_ERROR(status))
target_if_debug("thermal stats level response failed.");
return 0;
}
/**
* target_if_fwol_register_thermal_throttle_handler() - Register handler for
* thermal throttle stats firmware event
* @psoc: psoc object
*
* Return: void
*/
static void
target_if_fwol_register_thermal_throttle_handler(struct wlan_objmgr_psoc *psoc)
{
QDF_STATUS status;
struct wlan_fwol_psoc_obj *fwol_obj;
fwol_obj = fwol_get_psoc_obj(psoc);
if (!fwol_obj) {
target_if_err("Failed to get FWOL Obj");
return;
}
if (!target_if_fwol_is_thermal_stats_enable(fwol_obj)) {
target_if_debug("thermal stats offload not enabled");
return;
}
status = wmi_unified_register_event_handler(
get_wmi_unified_hdl_from_psoc(psoc),
wmi_tt_stats_event_id,
target_if_fwol_thermal_throttle_event_handler,
WMI_RX_SERIALIZER_CTX);
if (QDF_IS_STATUS_ERROR(status))
target_if_debug("Failed to register thermal stats event cb");
}
/**
* target_if_fwol_unregister_thermal_stats_handler() - Register handler for
* thermal throttle stats firmware event
* @psoc: psoc object
*
* Return: void
*/
static void
target_if_fwol_unregister_thermal_throttle_handler(
struct wlan_objmgr_psoc *psoc)
{
QDF_STATUS status;
status = wmi_unified_unregister_event_handler(
get_wmi_unified_hdl_from_psoc(psoc),
wmi_tt_stats_event_id);
if (QDF_IS_STATUS_ERROR(status))
target_if_debug("Failed to unregister thermal stats event cb");
}
#else
static void
target_if_fwol_register_thermal_throttle_handler(struct wlan_objmgr_psoc *psoc)
{
}
static void
target_if_fwol_unregister_thermal_throttle_handler(
struct wlan_objmgr_psoc *psoc)
{
}
static void
target_if_fwol_register_thermal_stats_tx_ops(struct wlan_fwol_tx_ops *tx_ops)
{
}
#endif
QDF_STATUS target_if_fwol_register_event_handler(struct wlan_objmgr_psoc *psoc,
void *arg)
{
target_if_fwol_register_elna_event_handler(psoc, arg);
target_if_fwol_register_thermal_throttle_handler(psoc);
return QDF_STATUS_SUCCESS;
}
@ -253,6 +446,7 @@ target_if_fwol_unregister_event_handler(struct wlan_objmgr_psoc *psoc,
void *arg)
{
target_if_fwol_unregister_elna_event_handler(psoc, arg);
target_if_fwol_unregister_thermal_throttle_handler(psoc);
return QDF_STATUS_SUCCESS;
}
@ -261,6 +455,7 @@ QDF_STATUS target_if_fwol_register_tx_ops(struct wlan_fwol_tx_ops *tx_ops)
{
target_if_fwol_register_elna_tx_ops(tx_ops);
target_if_fwol_register_dscp_up_tx_ops(tx_ops);
target_if_fwol_register_thermal_stats_tx_ops(tx_ops);
tx_ops->reg_evt_handler = target_if_fwol_register_event_handler;
tx_ops->unreg_evt_handler = target_if_fwol_unregister_event_handler;

View file

@ -207,6 +207,8 @@ CONFIG_QCOM_TDLS := y
CONFIG_WLAN_SYSFS := y
CONFIG_THERMAL_STATS_SUPPORT := y
ifeq ($(CONFIG_WLAN_SYSFS), y)
CONFIG_WLAN_SYSFS_STA_INFO := y
CONFIG_WLAN_SYSFS_CHANNEL := y

View file

@ -2213,6 +2213,9 @@ struct hdd_context {
qdf_work_t twt_en_dis_work;
#endif
bool dump_in_progress;
#ifdef THERMAL_STATS_SUPPORT
bool is_therm_stats_in_progress;
#endif
};
/**

View file

@ -196,6 +196,7 @@
#include "wlan_cm_roam_ucfg_api.h"
#include <cdp_txrx_ctrl.h>
#include "qdf_lock.h"
#include "wlan_hdd_thermal.h"
#ifdef MODULE
#define WLAN_MODULE_NAME module_name(THIS_MODULE)
@ -13887,6 +13888,17 @@ static int hdd_init_mws_coex(struct hdd_context *hdd_ctx)
}
#endif
#ifdef THERMAL_STATS_SUPPORT
static void hdd_thermal_stats_cmd_init(struct hdd_context *hdd_ctx)
{
hdd_send_get_thermal_stats_cmd(hdd_ctx, thermal_stats_init, NULL, NULL);
}
#else
static void hdd_thermal_stats_cmd_init(struct hdd_context *hdd_ctx)
{
}
#endif
/**
* hdd_features_init() - Init features
* @hdd_ctx: HDD context
@ -14001,6 +14013,7 @@ static int hdd_features_init(struct hdd_context *hdd_ctx)
wlan_cm_set_6ghz_key_mgmt_mask(hdd_ctx->psoc,
ALLOWED_KEYMGMT_6G_MASK);
}
hdd_thermal_stats_cmd_init(hdd_ctx);
hdd_exit();
return 0;

View file

@ -36,8 +36,12 @@
#include <qca_vendor.h>
#include "wlan_fwol_ucfg_api.h"
#include <pld_common.h>
#include "os_if_fwol.h"
#include "wlan_osif_request_manager.h"
#include "wlan_fwol_public_structs.h"
#define DC_OFF_PERCENT_WPPS 50
#define WLAN_WAIT_TIME_GET_THERM_LVL 1000
const struct nla_policy
wlan_hdd_thermal_mitigation_policy
@ -143,6 +147,223 @@ hdd_send_thermal_mitigation_val(struct hdd_context *hdd_ctx, uint32_t level,
return QDF_STATUS_SUCCESS;
}
#ifdef THERMAL_STATS_SUPPORT
QDF_STATUS
hdd_send_get_thermal_stats_cmd(struct hdd_context *hdd_ctx,
enum thermal_stats_request_type request_type,
void (*callback)(void *context,
struct thermal_throttle_info *response),
void *context)
{
int ret;
if (!hdd_ctx->psoc) {
hdd_err_rl("NULL pointer for psoc");
return QDF_STATUS_E_INVAL;
}
/* Send Get Thermal Stats cmd to FW */
ret = os_if_fwol_get_thermal_stats_req(hdd_ctx->psoc, request_type,
callback, context);
if (ret)
return QDF_STATUS_E_FAILURE;
return QDF_STATUS_SUCCESS;
}
/**
* hdd_get_thermal_stats_cb() - Get thermal stats callback
* @context: Call context
* @response: Pointer to response structure
*
* Return: void
*/
static void
hdd_get_thermal_stats_cb(void *context,
struct thermal_throttle_info *response)
{
struct osif_request *request;
struct thermal_throttle_info *priv;
request = osif_request_get(context);
if (!request) {
osif_err("Obsolete request");
return;
}
priv = osif_request_priv(request);
qdf_mem_copy(priv, response, sizeof(struct thermal_throttle_info));
osif_request_complete(request);
osif_request_put(request);
}
#define THERMAL_MIN_TEMP QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MIN_TEMPERATURE
#define THERMAL_MAX_TEMP QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MAX_TEMPERATURE
#define THERMAL_DWELL_TIME QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_DWELL_TIME
#define THERMAL_LVL_COUNT QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_TEMP_LEVEL_COUNTER
/**
* hdd_get_curr_thermal_stats_val() - Indicate thermal stats
* to upper layer when query vendor command
* @wiphy: Pointer to wireless phy
* @hdd_ctx: hdd context
*
* Return: 0 for success
*/
static int
hdd_get_curr_thermal_stats_val(struct wiphy *wiphy,
struct hdd_context *hdd_ctx)
{
int ret = 0;
uint8_t i = 0;
struct osif_request *request = NULL;
int skb_len = 0;
struct thermal_throttle_info *priv;
struct thermal_throttle_info *get_tt_stats = NULL;
struct sk_buff *skb = NULL;
void *cookie;
struct nlattr *therm_attr;
struct nlattr *tt_levels;
static const struct osif_request_params params = {
.priv_size = sizeof(*priv),
.timeout_ms = WLAN_WAIT_TIME_GET_THERM_LVL,
.dealloc = NULL,
};
if (hdd_ctx->is_therm_stats_in_progress) {
hdd_err("request already in progress");
return -EINVAL;
}
request = osif_request_alloc(&params);
if (!request) {
hdd_err("request allocation failure");
return -ENOMEM;
}
cookie = osif_request_cookie(request);
hdd_ctx->is_therm_stats_in_progress = true;
ret = hdd_send_get_thermal_stats_cmd(hdd_ctx, thermal_stats_req,
hdd_get_thermal_stats_cb,
cookie);
if (QDF_IS_STATUS_ERROR(ret)) {
hdd_err("Failure while sending command to fw");
ret = -EAGAIN;
goto completed;
}
ret = osif_request_wait_for_response(request);
if (ret) {
hdd_err("Timed out while retrieving thermal stats");
ret = -EAGAIN;
goto completed;
}
get_tt_stats = osif_request_priv(request);
if (!get_tt_stats) {
hdd_err("invalid get_tt_stats");
ret = -EINVAL;
goto completed;
}
skb_len = NLMSG_HDRLEN + (get_tt_stats->therm_throt_levels) *
(NLA_HDRLEN + (NLA_HDRLEN +
sizeof(get_tt_stats->level_info[i].start_temp_level) +
NLA_HDRLEN +
sizeof(get_tt_stats->level_info[i].end_temp_level) +
NLA_HDRLEN +
sizeof(get_tt_stats->level_info[i].total_time_ms_lo) +
NLA_HDRLEN +
sizeof(get_tt_stats->level_info[i].num_entry)));
skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
skb_len);
if (!skb) {
hdd_err_rl("cfg80211_vendor_cmd_alloc_reply_skb failed");
ret = -ENOMEM;
goto completed;
}
therm_attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_THERMAL_STATS);
if (!therm_attr) {
hdd_err_rl("nla_nest_start failed for attr failed");
ret = -EINVAL;
goto completed;
}
for (i = 0; i < get_tt_stats->therm_throt_levels; i++) {
tt_levels = nla_nest_start(skb, i);
if (!tt_levels) {
hdd_err_rl("nla_nest_start failed for thermal level %d",
i);
ret = -EINVAL;
goto completed;
}
hdd_debug("level %d, Temp Range: %d - %d, Dwell time %d, Counter %d",
i, get_tt_stats->level_info[i].start_temp_level,
get_tt_stats->level_info[i].end_temp_level,
get_tt_stats->level_info[i].total_time_ms_lo,
get_tt_stats->level_info[i].num_entry);
if (nla_put_u32(skb, THERMAL_MIN_TEMP,
get_tt_stats->level_info[i].start_temp_level) ||
nla_put_u32(skb, THERMAL_MAX_TEMP,
get_tt_stats->level_info[i].end_temp_level) ||
nla_put_u32(skb, THERMAL_DWELL_TIME,
(get_tt_stats->level_info[i].total_time_ms_lo)) ||
nla_put_u32(skb, THERMAL_LVL_COUNT,
get_tt_stats->level_info[i].num_entry)) {
hdd_err("nla put failure");
kfree_skb(skb);
ret = -EINVAL;
hdd_ctx->is_therm_stats_in_progress = false;
break;
}
nla_nest_end(skb, tt_levels);
}
nla_nest_end(skb, therm_attr);
wlan_cfg80211_vendor_cmd_reply(skb);
completed:
hdd_ctx->is_therm_stats_in_progress = false;
osif_request_put(request);
return ret;
}
#undef THERMAL_MIN_TEMP
#undef THERMAL_MAX_TEMP
#undef THERMAL_DWELL_TIME
#undef THERMAL_LVL_COUNT
static QDF_STATUS
hdd_send_thermal_stats_clear_cmd(struct hdd_context *hdd_ctx)
{
QDF_STATUS status;
status = hdd_send_get_thermal_stats_cmd(hdd_ctx,
thermal_stats_clear, NULL,
NULL);
return status;
}
#else
static int
hdd_get_curr_thermal_stats_val(struct wiphy *wiphy,
struct hdd_context *hdd_ctx)
{
return -EINVAL;
}
static QDF_STATUS
hdd_send_thermal_stats_clear_cmd(struct hdd_context *hdd_ctx)
{
return QDF_STATUS_E_NOSUPPORT;
}
#endif /* THERMAL_STATS_SUPPORT */
/**
* __wlan_hdd_cfg80211_set_thermal_mitigation_policy() - Set the thermal policy
* @wiphy: Pointer to wireless phy
@ -162,9 +383,14 @@ __wlan_hdd_cfg80211_set_thermal_mitigation_policy(struct wiphy *wiphy,
struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX + 1];
uint32_t level, cmd_type;
QDF_STATUS status;
int ret;
hdd_enter();
ret = wlan_hdd_validate_context(hdd_ctx);
if (ret)
return -EINVAL;
if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
hdd_err_rl("Command not allowed in FTM mode");
return -EPERM;
@ -184,23 +410,35 @@ __wlan_hdd_cfg80211_set_thermal_mitigation_policy(struct wiphy *wiphy,
}
cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE]);
if (cmd_type != QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL) {
hdd_err_rl("invalid thermal cmd value");
return -EINVAL;
switch (cmd_type) {
case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL:
if (!tb[QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL]) {
hdd_err_rl("attr thermal throttle set failed");
return -EINVAL;
}
level = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL]);
hdd_debug("thermal mitigation level from userspace %d", level);
status = hdd_send_thermal_mitigation_val(hdd_ctx, level,
THERMAL_MONITOR_APPS);
ret = qdf_status_to_os_return(status);
break;
case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_THERMAL_STATS:
ret = hdd_get_curr_thermal_stats_val(wiphy, hdd_ctx);
break;
case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_CLEAR_THERMAL_STATS:
status = hdd_send_thermal_stats_clear_cmd(hdd_ctx);
if (QDF_IS_STATUS_ERROR(status)) {
hdd_err("Failure while sending command to fw");
ret = -EINVAL;
}
break;
default:
ret = -EINVAL;
}
if (!tb[QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL]) {
hdd_err_rl("attr thermal throttle set failed");
return -EINVAL;
}
level =
nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL]);
hdd_debug("thermal mitigation level from userspace %d", level);
status = hdd_send_thermal_mitigation_val(hdd_ctx, level,
THERMAL_MONITOR_APPS);
hdd_exit();
return qdf_status_to_os_return(status);
return ret;
}
/**

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@ -195,4 +195,13 @@ int wlan_hdd_pld_set_thermal_mitigation(struct device *dev,
}
#endif /* FEATURE_THERMAL_VENDOR_COMMANDS */
#ifdef THERMAL_STATS_SUPPORT
QDF_STATUS
hdd_send_get_thermal_stats_cmd(struct hdd_context *hdd_ctx,
enum thermal_stats_request_type request_type,
void (*callback)(void *context,
struct thermal_throttle_info *response),
void *context);
#endif /* THERMAL_STATS_SUPPORT */
#endif /* __HDD_THERMAL_H */

View file

@ -114,6 +114,7 @@
#endif
#include "wlan_pkt_capture_ucfg_api.h"
#include "wlan_fwol_ucfg_api.h"
#define WMA_LOG_COMPLETION_TIMER 3000 /* 3 seconds */
#define WMI_TLV_HEADROOM 128
@ -5804,10 +5805,52 @@ static void wma_set_mlme_caps(struct wlan_objmgr_psoc *psoc)
wma_err("Failed to set sae roam support");
}
#ifdef THERMAL_STATS_SUPPORT
static void wma_set_thermal_stats_fw_cap(tp_wma_handle wma,
struct wlan_fwol_capability_info *cap)
{
cap->fw_thermal_stats_cap = wmi_service_enabled(wma->wmi_handle,
wmi_service_thermal_stats_temp_range_supported);
}
#else
static void wma_set_thermal_stats_fw_cap(tp_wma_handle wma,
struct wlan_fwol_capability_info *cap)
{
}
#endif
/**
* wma_set_fwol_caps() - Populate fwol component related capabilities
* to the fwol component
*
* @psoc: Pointer to psoc object
*
* Return: None
*/
static void wma_set_fwol_caps(struct wlan_objmgr_psoc *psoc)
{
tp_wma_handle wma;
struct wlan_fwol_capability_info cap_info;
wma = cds_get_context(QDF_MODULE_ID_WMA);
if (!wma) {
wma_err_rl("wma Null");
return;
}
if (!psoc) {
wma_err_rl("psoc Null");
return;
}
wma_set_thermal_stats_fw_cap(wma, &cap_info);
ucfg_fwol_update_fw_cap_info(psoc, &cap_info);
}
static void wma_set_component_caps(struct wlan_objmgr_psoc *psoc)
{
wma_set_pmo_caps(psoc);
wma_set_mlme_caps(psoc);
wma_set_fwol_caps(psoc);
}
#if defined(WLAN_FEATURE_GTK_OFFLOAD) && defined(WLAN_POWER_MANAGEMENT_OFFLOAD)

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@ -26,6 +26,7 @@
#define __OS_IF_FWOL_H__
#include "wlan_objmgr_vdev_obj.h"
#include "wlan_fwol_public_structs.h"
#ifdef WLAN_FEATURE_ELNA
/**
@ -82,4 +83,12 @@ static inline int os_if_fwol_send_dscp_up_map_to_fw(
}
#endif /* WLAN_SEND_DSCP_UP_MAP_TO_FW */
#ifdef THERMAL_STATS_SUPPORT
int os_if_fwol_get_thermal_stats_req(struct wlan_objmgr_psoc *psoc,
enum thermal_stats_request_type req,
void (*callback)(void *context,
struct thermal_throttle_info *response),
void *context);
#endif /* THERMAL_STATS_SUPPORT */
#endif /* __OS_IF_FWOL_H__ */

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2019-2020 The Linux Foundation. All rights reserved.
* Copyright (c) 2019-2021 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@ -145,3 +145,23 @@ int os_if_fwol_send_dscp_up_map_to_fw(struct wlan_objmgr_vdev *vdev,
return qdf_status_to_os_return(status);
}
#endif
#ifdef THERMAL_STATS_SUPPORT
int os_if_fwol_get_thermal_stats_req(struct wlan_objmgr_psoc *psoc,
enum thermal_stats_request_type req,
void (*callback)(void *context,
struct thermal_throttle_info *response),
void *context)
{
QDF_STATUS status;
status = ucfg_fwol_send_get_thermal_stats_cmd(psoc, req, callback,
context);
if (!QDF_IS_STATUS_SUCCESS(status))
osif_err("Failed to send get thermal stats cmd to FW, %d",
status);
return qdf_status_to_os_return(status);
}
#endif