diff --git a/Kbuild b/Kbuild index 02704aa418cd..004d3e47406a 100644 --- a/Kbuild +++ b/Kbuild @@ -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 diff --git a/components/fw_offload/core/inc/wlan_fw_offload_main.h b/components/fw_offload/core/inc/wlan_fw_offload_main.h index 756c0cff1c22..1c40671c85a0 100644 --- a/components/fw_offload/core/inc/wlan_fw_offload_main.h +++ b/components/fw_offload/core/inc/wlan_fw_offload_main.h @@ -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 }; }; diff --git a/components/fw_offload/core/src/wlan_fw_offload_main.c b/components/fw_offload/core/src/wlan_fw_offload_main.c index 88539722502a..bc429b87fe7f 100644 --- a/components/fw_offload/core/src/wlan_fw_offload_main.c +++ b/components/fw_offload/core/src/wlan_fw_offload_main.c @@ -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; diff --git a/components/fw_offload/dispatcher/inc/cfg_thermal_temp.h b/components/fw_offload/dispatcher/inc/cfg_thermal_temp.h index e91b21dda32d..afcca4faa1dc 100644 --- a/components/fw_offload/dispatcher/inc/cfg_thermal_temp.h +++ b/components/fw_offload/dispatcher/inc/cfg_thermal_temp.h @@ -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") +/* + * 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 + * + * + */ +#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 diff --git a/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h b/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h index 10f253a8bb90..cf3c30aec0e0 100644 --- a/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h +++ b/components/fw_offload/dispatcher/inc/wlan_fwol_public_structs.h @@ -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_ */ diff --git a/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h b/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h index 44f6148f4e99..e69674368565 100644 --- a/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h +++ b/components/fw_offload/dispatcher/inc/wlan_fwol_ucfg_api.h @@ -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 diff --git a/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c b/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c index a8f88506b934..984f9ad846bf 100644 --- a/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c +++ b/components/fw_offload/dispatcher/src/wlan_fwol_tgt_api.c @@ -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; } diff --git a/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c b/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c index 4d966aaeaaa5..af4dbf45abe1 100644 --- a/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c +++ b/components/fw_offload/dispatcher/src/wlan_fwol_ucfg_api.c @@ -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) { diff --git a/components/target_if/fw_offload/src/target_if_fwol.c b/components/target_if/fw_offload/src/target_if_fwol.c index 11b651068c8f..124418889085 100644 --- a/components/target_if/fw_offload/src/target_if_fwol.c +++ b/components/target_if/fw_offload/src/target_if_fwol.c @@ -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; diff --git a/configs/default_defconfig b/configs/default_defconfig index b5ff35d4aab8..84d823a15564 100644 --- a/configs/default_defconfig +++ b/configs/default_defconfig @@ -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 diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index bde9ab586ca4..044204bbcddd 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -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 }; /** diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index 80e0c50c269c..677abe3abf00 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -196,6 +196,7 @@ #include "wlan_cm_roam_ucfg_api.h" #include #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; diff --git a/core/hdd/src/wlan_hdd_thermal.c b/core/hdd/src/wlan_hdd_thermal.c index 950eeb911cc2..18015a1cd5a2 100644 --- a/core/hdd/src/wlan_hdd_thermal.c +++ b/core/hdd/src/wlan_hdd_thermal.c @@ -36,8 +36,12 @@ #include #include "wlan_fwol_ucfg_api.h" #include +#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(¶ms); + 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; } /** diff --git a/core/hdd/src/wlan_hdd_thermal.h b/core/hdd/src/wlan_hdd_thermal.h index 3bfcbd490361..a18abe7f19ae 100644 --- a/core/hdd/src/wlan_hdd_thermal.h +++ b/core/hdd/src/wlan_hdd_thermal.h @@ -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 */ diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 4c330b267eaa..16812d9723fb 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -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) diff --git a/os_if/fw_offload/inc/os_if_fwol.h b/os_if/fw_offload/inc/os_if_fwol.h index 8ecbc0ff2145..2c938c1a94c1 100644 --- a/os_if/fw_offload/inc/os_if_fwol.h +++ b/os_if/fw_offload/inc/os_if_fwol.h @@ -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__ */ diff --git a/os_if/fw_offload/src/os_if_fwol.c b/os_if/fw_offload/src/os_if_fwol.c index 90ee99744f5e..de2dd43d8f31 100644 --- a/os_if/fw_offload/src/os_if_fwol.c +++ b/os_if/fw_offload/src/os_if_fwol.c @@ -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