xref: /wlan-driver/qcacld-3.0/core/hdd/src/wlan_hdd_thermal.c (revision 5113495b16420b49004c444715d2daae2066e7dc)
1*5113495bSYour Name /*
2*5113495bSYour Name  * Copyright (c) 2020-2021 The Linux Foundation. All rights reserved.
3*5113495bSYour Name  * Copyright (c) 2021-2022 Qualcomm Innovation Center, Inc. All rights reserved.
4*5113495bSYour Name  *
5*5113495bSYour Name  * Permission to use, copy, modify, and/or distribute this software for
6*5113495bSYour Name  * any purpose with or without fee is hereby granted, provided that the
7*5113495bSYour Name  * above copyright notice and this permission notice appear in all
8*5113495bSYour Name  * copies.
9*5113495bSYour Name  *
10*5113495bSYour Name  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
11*5113495bSYour Name  * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
12*5113495bSYour Name  * WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
13*5113495bSYour Name  * AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
14*5113495bSYour Name  * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
15*5113495bSYour Name  * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
16*5113495bSYour Name  * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17*5113495bSYour Name  * PERFORMANCE OF THIS SOFTWARE.
18*5113495bSYour Name  */
19*5113495bSYour Name 
20*5113495bSYour Name /**
21*5113495bSYour Name  * DOC: wlan_hdd_thermal.c
22*5113495bSYour Name  *
23*5113495bSYour Name  * WLAN Host Device Driver implementation for thermal mitigation handling
24*5113495bSYour Name  */
25*5113495bSYour Name 
26*5113495bSYour Name #include <wlan_hdd_includes.h>
27*5113495bSYour Name #include <net/cfg80211.h>
28*5113495bSYour Name #include "wlan_osif_priv.h"
29*5113495bSYour Name #include "qdf_trace.h"
30*5113495bSYour Name #include "wlan_hdd_main.h"
31*5113495bSYour Name #include "osif_sync.h"
32*5113495bSYour Name #include <linux/limits.h>
33*5113495bSYour Name #include <wlan_hdd_object_manager.h>
34*5113495bSYour Name #include "sme_api.h"
35*5113495bSYour Name #include "wlan_hdd_thermal.h"
36*5113495bSYour Name #include "wlan_hdd_cfg80211.h"
37*5113495bSYour Name #include <qca_vendor.h>
38*5113495bSYour Name #include "wlan_fwol_ucfg_api.h"
39*5113495bSYour Name #include <pld_common.h>
40*5113495bSYour Name #include "wlan_hdd_stats.h"
41*5113495bSYour Name #include "os_if_fwol.h"
42*5113495bSYour Name #include "wlan_osif_request_manager.h"
43*5113495bSYour Name #include "wlan_fwol_public_structs.h"
44*5113495bSYour Name 
45*5113495bSYour Name #define DC_OFF_PERCENT_WPPS 50
46*5113495bSYour Name #define WLAN_WAIT_TIME_GET_THERM_LVL 1000
47*5113495bSYour Name 
48*5113495bSYour Name const struct nla_policy
49*5113495bSYour Name 	wlan_hdd_thermal_mitigation_policy
50*5113495bSYour Name 	[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX + 1] = {
51*5113495bSYour Name 		[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE] = {.type = NLA_U32},
52*5113495bSYour Name 		[QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL] = {
53*5113495bSYour Name 						.type = NLA_U32},
54*5113495bSYour Name 		[QCA_WLAN_VENDOR_ATTR_THERMAL_COMPLETION_WINDOW] = {
55*5113495bSYour Name 						.type = NLA_U32},
56*5113495bSYour Name 		[QCA_WLAN_VENDOR_ATTR_THERMAL_STATS] = {.type = NLA_NESTED},
57*5113495bSYour Name };
58*5113495bSYour Name 
59*5113495bSYour Name #ifdef FEATURE_WPSS_THERMAL_MITIGATION
60*5113495bSYour Name void
hdd_thermal_fill_clientid_priority(struct hdd_context * hdd_ctx,uint8_t mon_id,uint8_t priority_apps,uint8_t priority_wpps,struct thermal_mitigation_params * params)61*5113495bSYour Name hdd_thermal_fill_clientid_priority(struct hdd_context *hdd_ctx, uint8_t mon_id,
62*5113495bSYour Name 				   uint8_t priority_apps, uint8_t priority_wpps,
63*5113495bSYour Name 				   struct thermal_mitigation_params *params)
64*5113495bSYour Name {
65*5113495bSYour Name 	if (hdd_ctx->multi_client_thermal_mitigation) {
66*5113495bSYour Name 		if (mon_id == THERMAL_MONITOR_APPS) {
67*5113495bSYour Name 			params->priority  = priority_apps;
68*5113495bSYour Name 			params->client_id = mon_id;
69*5113495bSYour Name 			hdd_debug("Thermal client:%d priority_apps: %d", mon_id,
70*5113495bSYour Name 				  priority_apps);
71*5113495bSYour Name 		} else if (mon_id == THERMAL_MONITOR_WPSS) {
72*5113495bSYour Name 			params->priority = priority_wpps;
73*5113495bSYour Name 			params->client_id = mon_id;
74*5113495bSYour Name 			/* currently hardcoded,
75*5113495bSYour Name 			 * can be changed based on requirement.
76*5113495bSYour Name 			 */
77*5113495bSYour Name 			params->levelconf[0].dcoffpercent = DC_OFF_PERCENT_WPPS;
78*5113495bSYour Name 			hdd_debug("Thermal client:%d priority_wpps: %d", mon_id,
79*5113495bSYour Name 				  priority_wpps);
80*5113495bSYour Name 		}
81*5113495bSYour Name 	}
82*5113495bSYour Name }
83*5113495bSYour Name #endif
84*5113495bSYour Name 
85*5113495bSYour Name QDF_STATUS
hdd_send_thermal_mitigation_val(struct hdd_context * hdd_ctx,uint32_t level,uint8_t mon_id)86*5113495bSYour Name hdd_send_thermal_mitigation_val(struct hdd_context *hdd_ctx, uint32_t level,
87*5113495bSYour Name 				uint8_t mon_id)
88*5113495bSYour Name {
89*5113495bSYour Name 	uint32_t dc, dc_off_percent;
90*5113495bSYour Name 	uint32_t prio = 0, target_temp = 0;
91*5113495bSYour Name 	struct wlan_fwol_thermal_temp thermal_temp = {0};
92*5113495bSYour Name 	QDF_STATUS status;
93*5113495bSYour Name 	bool enable = true;
94*5113495bSYour Name 	struct thermal_mitigation_params therm_cfg_params = {0};
95*5113495bSYour Name 
96*5113495bSYour Name 	status = ucfg_fwol_get_thermal_temp(hdd_ctx->psoc, &thermal_temp);
97*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
98*5113495bSYour Name 		hdd_err_rl("Failed to get fwol thermal obj");
99*5113495bSYour Name 		return status;
100*5113495bSYour Name 	}
101*5113495bSYour Name 
102*5113495bSYour Name 	switch (level) {
103*5113495bSYour Name 	case QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY:
104*5113495bSYour Name 		dc_off_percent = thermal_temp.throttle_dutycycle_level[5];
105*5113495bSYour Name 		break;
106*5113495bSYour Name 	case QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL:
107*5113495bSYour Name 		dc_off_percent = thermal_temp.throttle_dutycycle_level[4];
108*5113495bSYour Name 		break;
109*5113495bSYour Name 	case QCA_WLAN_VENDOR_THERMAL_LEVEL_SEVERE:
110*5113495bSYour Name 		dc_off_percent = thermal_temp.throttle_dutycycle_level[3];
111*5113495bSYour Name 		break;
112*5113495bSYour Name 	case QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE:
113*5113495bSYour Name 		dc_off_percent = thermal_temp.throttle_dutycycle_level[2];
114*5113495bSYour Name 		break;
115*5113495bSYour Name 	case QCA_WLAN_VENDOR_THERMAL_LEVEL_LIGHT:
116*5113495bSYour Name 		dc_off_percent = thermal_temp.throttle_dutycycle_level[1];
117*5113495bSYour Name 		break;
118*5113495bSYour Name 	case QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE:
119*5113495bSYour Name 		enable = false;
120*5113495bSYour Name 		dc_off_percent = thermal_temp.throttle_dutycycle_level[0];
121*5113495bSYour Name 		break;
122*5113495bSYour Name 	default:
123*5113495bSYour Name 		hdd_debug("Invalid thermal state");
124*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
125*5113495bSYour Name 	}
126*5113495bSYour Name 
127*5113495bSYour Name 	dc = thermal_temp.thermal_sampling_time;
128*5113495bSYour Name 	therm_cfg_params.enable = enable;
129*5113495bSYour Name 	therm_cfg_params.dc = dc;
130*5113495bSYour Name 	therm_cfg_params.levelconf[0].dcoffpercent = dc_off_percent;
131*5113495bSYour Name 	therm_cfg_params.levelconf[0].priority = prio;
132*5113495bSYour Name 	therm_cfg_params.levelconf[0].tmplwm = target_temp;
133*5113495bSYour Name 	therm_cfg_params.num_thermal_conf = 1;
134*5113495bSYour Name 	therm_cfg_params.pdev_id = 0;
135*5113495bSYour Name 
136*5113495bSYour Name 	hdd_thermal_fill_clientid_priority(hdd_ctx, mon_id,
137*5113495bSYour Name 					   thermal_temp.priority_apps,
138*5113495bSYour Name 					   thermal_temp.priority_wpps,
139*5113495bSYour Name 					   &therm_cfg_params);
140*5113495bSYour Name 
141*5113495bSYour Name 	hdd_debug("dc %d dc_off_per %d", dc, dc_off_percent);
142*5113495bSYour Name 
143*5113495bSYour Name 	status = sme_set_thermal_throttle_cfg(hdd_ctx->mac_handle,
144*5113495bSYour Name 					      &therm_cfg_params);
145*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
146*5113495bSYour Name 		hdd_err_rl("Failed to set throttle configuration %d", status);
147*5113495bSYour Name 
148*5113495bSYour Name 	else
149*5113495bSYour Name 		/*
150*5113495bSYour Name 		 * After SSR, the thermal mitigation level is lost.
151*5113495bSYour Name 		 * As SSR is hidden from userland, this command will not come
152*5113495bSYour Name 		 * from userspace after a SSR. To restore this configuration,
153*5113495bSYour Name 		 * save this in hdd context and restore after re-init.
154*5113495bSYour Name 		 */
155*5113495bSYour Name 		hdd_ctx->dutycycle_off_percent = dc_off_percent;
156*5113495bSYour Name 
157*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
158*5113495bSYour Name }
159*5113495bSYour Name 
160*5113495bSYour Name /**
161*5113495bSYour Name  * convert_level_to_vendor_thermal_level() - convert internal thermal level
162*5113495bSYour Name  *  to vendor command attribute enum qca_wlan_vendor_thermal_level
163*5113495bSYour Name  * @level: driver internal thermal level
164*5113495bSYour Name  *
165*5113495bSYour Name  * Return: vendor thermal level
166*5113495bSYour Name  */
167*5113495bSYour Name static enum qca_wlan_vendor_thermal_level
convert_level_to_vendor_thermal_level(enum thermal_throttle_level level)168*5113495bSYour Name convert_level_to_vendor_thermal_level(enum thermal_throttle_level level)
169*5113495bSYour Name {
170*5113495bSYour Name 	if (level == THERMAL_FULLPERF)
171*5113495bSYour Name 		return QCA_WLAN_VENDOR_THERMAL_LEVEL_NONE;
172*5113495bSYour Name 	else if (level == THERMAL_MITIGATION)
173*5113495bSYour Name 		return QCA_WLAN_VENDOR_THERMAL_LEVEL_MODERATE;
174*5113495bSYour Name 	else if (level == THERMAL_SHUTOFF)
175*5113495bSYour Name 		return QCA_WLAN_VENDOR_THERMAL_LEVEL_CRITICAL;
176*5113495bSYour Name 	else
177*5113495bSYour Name 		return QCA_WLAN_VENDOR_THERMAL_LEVEL_EMERGENCY;
178*5113495bSYour Name }
179*5113495bSYour Name 
180*5113495bSYour Name /**
181*5113495bSYour Name  * hdd_get_curr_thermal_throttle_level_val() - Indicate current target
182*5113495bSYour Name  *  thermal throttle level to upper layer upon query level
183*5113495bSYour Name  * @hdd_ctx: hdd context
184*5113495bSYour Name  *
185*5113495bSYour Name  * Return: 0 for success
186*5113495bSYour Name  */
187*5113495bSYour Name static int
hdd_get_curr_thermal_throttle_level_val(struct hdd_context * hdd_ctx)188*5113495bSYour Name hdd_get_curr_thermal_throttle_level_val(struct hdd_context *hdd_ctx)
189*5113495bSYour Name {
190*5113495bSYour Name 	struct sk_buff *reply_skb;
191*5113495bSYour Name 	uint32_t data_len;
192*5113495bSYour Name 	enum thermal_throttle_level level = THERMAL_FULLPERF;
193*5113495bSYour Name 	enum qca_wlan_vendor_thermal_level vendor_level;
194*5113495bSYour Name 	QDF_STATUS status;
195*5113495bSYour Name 
196*5113495bSYour Name 	status = ucfg_fwol_thermal_get_target_level(hdd_ctx->psoc, &level);
197*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
198*5113495bSYour Name 		hdd_err("get_thermal level: fail get target level");
199*5113495bSYour Name 		return -EINVAL;
200*5113495bSYour Name 	}
201*5113495bSYour Name 	vendor_level = convert_level_to_vendor_thermal_level(level);
202*5113495bSYour Name 	data_len = NLMSG_HDRLEN + nla_total_size(sizeof(uint32_t));
203*5113495bSYour Name 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
204*5113495bSYour Name 							     data_len);
205*5113495bSYour Name 	if (!reply_skb) {
206*5113495bSYour Name 		hdd_err("get_thermal level: buffer alloc fail");
207*5113495bSYour Name 		return -ENOMEM;
208*5113495bSYour Name 	}
209*5113495bSYour Name 	if (nla_put_u32(reply_skb, QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL,
210*5113495bSYour Name 			vendor_level)) {
211*5113495bSYour Name 		hdd_err("get_thermal level: nla put fail");
212*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(reply_skb);
213*5113495bSYour Name 		return -EINVAL;
214*5113495bSYour Name 	}
215*5113495bSYour Name 	hdd_debug("get_thermal level: %d vendor level %d", level,
216*5113495bSYour Name 		  vendor_level);
217*5113495bSYour Name 
218*5113495bSYour Name 	return wlan_cfg80211_vendor_cmd_reply(reply_skb);
219*5113495bSYour Name }
220*5113495bSYour Name 
221*5113495bSYour Name /**
222*5113495bSYour Name  * hdd_get_curr_thermal_temperature_val() - Indicate current target
223*5113495bSYour Name  *  thermal temperature to upper layer when handing temperature
224*5113495bSYour Name  *  query vendor command
225*5113495bSYour Name  * @hdd_ctx: hdd context
226*5113495bSYour Name  * @adapter: adapter context
227*5113495bSYour Name  *
228*5113495bSYour Name  * Return: 0 for success
229*5113495bSYour Name  */
230*5113495bSYour Name static int
hdd_get_curr_thermal_temperature_val(struct hdd_context * hdd_ctx,struct hdd_adapter * adapter)231*5113495bSYour Name hdd_get_curr_thermal_temperature_val(struct hdd_context *hdd_ctx,
232*5113495bSYour Name 				     struct hdd_adapter *adapter)
233*5113495bSYour Name {
234*5113495bSYour Name 	struct sk_buff *reply_skb;
235*5113495bSYour Name 	int ret;
236*5113495bSYour Name 	uint32_t data_len;
237*5113495bSYour Name 	int temperature = 0;
238*5113495bSYour Name 
239*5113495bSYour Name 	ret = wlan_hdd_get_temperature(adapter, &temperature);
240*5113495bSYour Name 	if (ret)
241*5113495bSYour Name 		return ret;
242*5113495bSYour Name 	data_len = NLMSG_HDRLEN + nla_total_size(sizeof(uint32_t));
243*5113495bSYour Name 	reply_skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(hdd_ctx->wiphy,
244*5113495bSYour Name 							     data_len);
245*5113495bSYour Name 	if (!reply_skb) {
246*5113495bSYour Name 		hdd_err("get_thermal temperature: buffer alloc fail");
247*5113495bSYour Name 		return -ENOMEM;
248*5113495bSYour Name 	}
249*5113495bSYour Name 	if (nla_put_u32(reply_skb,
250*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_THERMAL_GET_TEMPERATURE_DATA,
251*5113495bSYour Name 			temperature)) {
252*5113495bSYour Name 		hdd_err("get_thermal temperature: nla put fail");
253*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(reply_skb);
254*5113495bSYour Name 		return -EINVAL;
255*5113495bSYour Name 	}
256*5113495bSYour Name 	hdd_debug("get_thermal temperature: %d", temperature);
257*5113495bSYour Name 
258*5113495bSYour Name 	return wlan_cfg80211_vendor_cmd_reply(reply_skb);
259*5113495bSYour Name }
260*5113495bSYour Name 
261*5113495bSYour Name #ifdef THERMAL_STATS_SUPPORT
262*5113495bSYour Name 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)263*5113495bSYour Name hdd_send_get_thermal_stats_cmd(struct hdd_context *hdd_ctx,
264*5113495bSYour Name 			       enum thermal_stats_request_type request_type,
265*5113495bSYour Name 			       void (*callback)(void *context,
266*5113495bSYour Name 			       struct thermal_throttle_info *response),
267*5113495bSYour Name 			       void *context)
268*5113495bSYour Name {
269*5113495bSYour Name 	int ret;
270*5113495bSYour Name 
271*5113495bSYour Name 	if (!hdd_ctx->psoc) {
272*5113495bSYour Name 		hdd_err_rl("NULL pointer for psoc");
273*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
274*5113495bSYour Name 	}
275*5113495bSYour Name 
276*5113495bSYour Name 
277*5113495bSYour Name 	/* Send Get Thermal Stats cmd to FW */
278*5113495bSYour Name 	ret = os_if_fwol_get_thermal_stats_req(hdd_ctx->psoc, request_type,
279*5113495bSYour Name 					       callback, context);
280*5113495bSYour Name 	if (ret)
281*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
282*5113495bSYour Name 
283*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
284*5113495bSYour Name }
285*5113495bSYour Name 
286*5113495bSYour Name /**
287*5113495bSYour Name  * hdd_get_thermal_stats_cb() - Get thermal stats callback
288*5113495bSYour Name  * @context: Call context
289*5113495bSYour Name  * @response: Pointer to response structure
290*5113495bSYour Name  *
291*5113495bSYour Name  * Return: void
292*5113495bSYour Name  */
293*5113495bSYour Name static void
hdd_get_thermal_stats_cb(void * context,struct thermal_throttle_info * response)294*5113495bSYour Name hdd_get_thermal_stats_cb(void *context,
295*5113495bSYour Name 			 struct thermal_throttle_info *response)
296*5113495bSYour Name {
297*5113495bSYour Name 	struct osif_request *request;
298*5113495bSYour Name 	struct thermal_throttle_info *priv;
299*5113495bSYour Name 
300*5113495bSYour Name 	request = osif_request_get(context);
301*5113495bSYour Name 	if (!request) {
302*5113495bSYour Name 		osif_err("Obsolete request");
303*5113495bSYour Name 		return;
304*5113495bSYour Name 	}
305*5113495bSYour Name 
306*5113495bSYour Name 	priv = osif_request_priv(request);
307*5113495bSYour Name 	qdf_mem_copy(priv, response, sizeof(struct thermal_throttle_info));
308*5113495bSYour Name 
309*5113495bSYour Name 	osif_request_complete(request);
310*5113495bSYour Name 	osif_request_put(request);
311*5113495bSYour Name }
312*5113495bSYour Name 
313*5113495bSYour Name #define THERMAL_MIN_TEMP QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MIN_TEMPERATURE
314*5113495bSYour Name #define THERMAL_MAX_TEMP QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_MAX_TEMPERATURE
315*5113495bSYour Name #define THERMAL_DWELL_TIME QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_DWELL_TIME
316*5113495bSYour Name #define THERMAL_LVL_COUNT QCA_WLAN_VENDOR_ATTR_THERMAL_STATS_TEMP_LEVEL_COUNTER
317*5113495bSYour Name 
318*5113495bSYour Name /**
319*5113495bSYour Name  * hdd_get_curr_thermal_stats_val() - Indicate thermal stats
320*5113495bSYour Name  *  to upper layer when query vendor command
321*5113495bSYour Name  * @wiphy: Pointer to wireless phy
322*5113495bSYour Name  * @hdd_ctx: hdd context
323*5113495bSYour Name  *
324*5113495bSYour Name  * Return: 0 for success
325*5113495bSYour Name  */
326*5113495bSYour Name static int
hdd_get_curr_thermal_stats_val(struct wiphy * wiphy,struct hdd_context * hdd_ctx)327*5113495bSYour Name hdd_get_curr_thermal_stats_val(struct wiphy *wiphy,
328*5113495bSYour Name 			       struct hdd_context *hdd_ctx)
329*5113495bSYour Name {
330*5113495bSYour Name 	int ret = 0;
331*5113495bSYour Name 	uint8_t i = 0;
332*5113495bSYour Name 	struct osif_request *request = NULL;
333*5113495bSYour Name 	int skb_len = 0;
334*5113495bSYour Name 	struct thermal_throttle_info *priv;
335*5113495bSYour Name 	struct thermal_throttle_info *get_tt_stats = NULL;
336*5113495bSYour Name 	struct sk_buff *skb = NULL;
337*5113495bSYour Name 	void *cookie;
338*5113495bSYour Name 	struct nlattr *therm_attr;
339*5113495bSYour Name 	struct nlattr *tt_levels;
340*5113495bSYour Name 	static const struct osif_request_params params = {
341*5113495bSYour Name 		.priv_size = sizeof(*priv),
342*5113495bSYour Name 		.timeout_ms = WLAN_WAIT_TIME_GET_THERM_LVL,
343*5113495bSYour Name 		.dealloc = NULL,
344*5113495bSYour Name 	};
345*5113495bSYour Name 
346*5113495bSYour Name 	if (hdd_ctx->is_therm_stats_in_progress) {
347*5113495bSYour Name 		hdd_err("request already in progress");
348*5113495bSYour Name 		return -EINVAL;
349*5113495bSYour Name 	}
350*5113495bSYour Name 
351*5113495bSYour Name 	request = osif_request_alloc(&params);
352*5113495bSYour Name 	if (!request) {
353*5113495bSYour Name 		hdd_err("request allocation failure");
354*5113495bSYour Name 		return -ENOMEM;
355*5113495bSYour Name 	}
356*5113495bSYour Name 	cookie = osif_request_cookie(request);
357*5113495bSYour Name 	hdd_ctx->is_therm_stats_in_progress = true;
358*5113495bSYour Name 	ret = hdd_send_get_thermal_stats_cmd(hdd_ctx, thermal_stats_req,
359*5113495bSYour Name 					     hdd_get_thermal_stats_cb,
360*5113495bSYour Name 					     cookie);
361*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(ret)) {
362*5113495bSYour Name 		hdd_err("Failure while sending command to fw");
363*5113495bSYour Name 		ret = -EAGAIN;
364*5113495bSYour Name 		goto completed;
365*5113495bSYour Name 	}
366*5113495bSYour Name 
367*5113495bSYour Name 	ret = osif_request_wait_for_response(request);
368*5113495bSYour Name 	if (ret) {
369*5113495bSYour Name 		hdd_err("Timed out while retrieving thermal stats");
370*5113495bSYour Name 		ret = -EAGAIN;
371*5113495bSYour Name 		goto completed;
372*5113495bSYour Name 	}
373*5113495bSYour Name 
374*5113495bSYour Name 	get_tt_stats = osif_request_priv(request);
375*5113495bSYour Name 	if (!get_tt_stats) {
376*5113495bSYour Name 		hdd_err("invalid get_tt_stats");
377*5113495bSYour Name 		ret = -EINVAL;
378*5113495bSYour Name 		goto completed;
379*5113495bSYour Name 	}
380*5113495bSYour Name 
381*5113495bSYour Name 	skb_len = NLMSG_HDRLEN + (get_tt_stats->therm_throt_levels) *
382*5113495bSYour Name 		  (NLA_HDRLEN + (NLA_HDRLEN +
383*5113495bSYour Name 		     sizeof(get_tt_stats->level_info[i].start_temp_level) +
384*5113495bSYour Name 		     NLA_HDRLEN +
385*5113495bSYour Name 		     sizeof(get_tt_stats->level_info[i].end_temp_level) +
386*5113495bSYour Name 		     NLA_HDRLEN +
387*5113495bSYour Name 		     sizeof(get_tt_stats->level_info[i].total_time_ms_lo) +
388*5113495bSYour Name 		     NLA_HDRLEN +
389*5113495bSYour Name 		     sizeof(get_tt_stats->level_info[i].num_entry)));
390*5113495bSYour Name 
391*5113495bSYour Name 	skb = wlan_cfg80211_vendor_cmd_alloc_reply_skb(wiphy,
392*5113495bSYour Name 						       skb_len);
393*5113495bSYour Name 	if (!skb) {
394*5113495bSYour Name 		hdd_err_rl("wlan_cfg80211_vendor_cmd_alloc_reply_skb failed");
395*5113495bSYour Name 		ret = -ENOMEM;
396*5113495bSYour Name 		goto completed;
397*5113495bSYour Name 	}
398*5113495bSYour Name 
399*5113495bSYour Name 	therm_attr = nla_nest_start(skb, QCA_WLAN_VENDOR_ATTR_THERMAL_STATS);
400*5113495bSYour Name 	if (!therm_attr) {
401*5113495bSYour Name 		hdd_err_rl("nla_nest_start failed for attr failed");
402*5113495bSYour Name 		ret = -EINVAL;
403*5113495bSYour Name 		goto nla_failed;
404*5113495bSYour Name 	}
405*5113495bSYour Name 
406*5113495bSYour Name 	for (i = 0; i < get_tt_stats->therm_throt_levels; i++) {
407*5113495bSYour Name 		tt_levels = nla_nest_start(skb, i);
408*5113495bSYour Name 		if (!tt_levels) {
409*5113495bSYour Name 			hdd_err_rl("nla_nest_start failed for thermal level %d",
410*5113495bSYour Name 				   i);
411*5113495bSYour Name 			ret = -EINVAL;
412*5113495bSYour Name 			goto nla_failed;
413*5113495bSYour Name 		}
414*5113495bSYour Name 
415*5113495bSYour Name 		hdd_debug("level %d, Temp Range: %d - %d, Dwell time %d, Counter %d",
416*5113495bSYour Name 			  i, get_tt_stats->level_info[i].start_temp_level,
417*5113495bSYour Name 			  get_tt_stats->level_info[i].end_temp_level,
418*5113495bSYour Name 			  get_tt_stats->level_info[i].total_time_ms_lo,
419*5113495bSYour Name 			  get_tt_stats->level_info[i].num_entry);
420*5113495bSYour Name 
421*5113495bSYour Name 		if (nla_put_u32(skb, THERMAL_MIN_TEMP,
422*5113495bSYour Name 				get_tt_stats->level_info[i].start_temp_level) ||
423*5113495bSYour Name 		    nla_put_u32(skb, THERMAL_MAX_TEMP,
424*5113495bSYour Name 				get_tt_stats->level_info[i].end_temp_level) ||
425*5113495bSYour Name 		    nla_put_u32(skb, THERMAL_DWELL_TIME,
426*5113495bSYour Name 				(get_tt_stats->level_info[i].total_time_ms_lo)) ||
427*5113495bSYour Name 		    nla_put_u32(skb, THERMAL_LVL_COUNT,
428*5113495bSYour Name 				get_tt_stats->level_info[i].num_entry)) {
429*5113495bSYour Name 			hdd_err("nla put failure");
430*5113495bSYour Name 			ret =  -EINVAL;
431*5113495bSYour Name 			goto nla_failed;
432*5113495bSYour Name 		}
433*5113495bSYour Name 		nla_nest_end(skb, tt_levels);
434*5113495bSYour Name 	}
435*5113495bSYour Name 	nla_nest_end(skb, therm_attr);
436*5113495bSYour Name 	wlan_cfg80211_vendor_cmd_reply(skb);
437*5113495bSYour Name 	goto completed;
438*5113495bSYour Name 
439*5113495bSYour Name nla_failed:
440*5113495bSYour Name 	wlan_cfg80211_vendor_free_skb(skb);
441*5113495bSYour Name completed:
442*5113495bSYour Name 	hdd_ctx->is_therm_stats_in_progress = false;
443*5113495bSYour Name 	osif_request_put(request);
444*5113495bSYour Name 
445*5113495bSYour Name 	return ret;
446*5113495bSYour Name }
447*5113495bSYour Name 
448*5113495bSYour Name #undef THERMAL_MIN_TEMP
449*5113495bSYour Name #undef THERMAL_MAX_TEMP
450*5113495bSYour Name #undef THERMAL_DWELL_TIME
451*5113495bSYour Name #undef THERMAL_LVL_COUNT
452*5113495bSYour Name 
453*5113495bSYour Name static QDF_STATUS
hdd_send_thermal_stats_clear_cmd(struct hdd_context * hdd_ctx)454*5113495bSYour Name hdd_send_thermal_stats_clear_cmd(struct hdd_context *hdd_ctx)
455*5113495bSYour Name {
456*5113495bSYour Name 	QDF_STATUS status;
457*5113495bSYour Name 
458*5113495bSYour Name 	status = hdd_send_get_thermal_stats_cmd(hdd_ctx,
459*5113495bSYour Name 					     thermal_stats_clear, NULL,
460*5113495bSYour Name 					     NULL);
461*5113495bSYour Name 
462*5113495bSYour Name 	return status;
463*5113495bSYour Name }
464*5113495bSYour Name #else
465*5113495bSYour Name static int
hdd_get_curr_thermal_stats_val(struct wiphy * wiphy,struct hdd_context * hdd_ctx)466*5113495bSYour Name hdd_get_curr_thermal_stats_val(struct wiphy *wiphy,
467*5113495bSYour Name 			       struct hdd_context *hdd_ctx)
468*5113495bSYour Name {
469*5113495bSYour Name 	return -EINVAL;
470*5113495bSYour Name }
471*5113495bSYour Name 
472*5113495bSYour Name static QDF_STATUS
hdd_send_thermal_stats_clear_cmd(struct hdd_context * hdd_ctx)473*5113495bSYour Name hdd_send_thermal_stats_clear_cmd(struct hdd_context *hdd_ctx)
474*5113495bSYour Name {
475*5113495bSYour Name 	return QDF_STATUS_E_NOSUPPORT;
476*5113495bSYour Name }
477*5113495bSYour Name #endif /* THERMAL_STATS_SUPPORT */
478*5113495bSYour Name 
479*5113495bSYour Name /**
480*5113495bSYour Name  * __wlan_hdd_cfg80211_set_thermal_mitigation_policy() - Set the thermal policy
481*5113495bSYour Name  * @wiphy: Pointer to wireless phy
482*5113495bSYour Name  * @wdev: Pointer to wireless device
483*5113495bSYour Name  * @data: Pointer to data
484*5113495bSYour Name  * @data_len: Length of @data
485*5113495bSYour Name  *
486*5113495bSYour Name  * Return: 0 on success, negative errno on failure
487*5113495bSYour Name  */
488*5113495bSYour Name static int
__wlan_hdd_cfg80211_set_thermal_mitigation_policy(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)489*5113495bSYour Name __wlan_hdd_cfg80211_set_thermal_mitigation_policy(struct wiphy *wiphy,
490*5113495bSYour Name 						  struct wireless_dev *wdev,
491*5113495bSYour Name 						  const void *data,
492*5113495bSYour Name 						  int data_len)
493*5113495bSYour Name {
494*5113495bSYour Name 	struct hdd_context *hdd_ctx = wiphy_priv(wiphy);
495*5113495bSYour Name 	struct net_device *dev = wdev->netdev;
496*5113495bSYour Name 	struct hdd_adapter *adapter = WLAN_HDD_GET_PRIV_PTR(dev);
497*5113495bSYour Name 	struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX + 1];
498*5113495bSYour Name 	uint32_t level, cmd_type;
499*5113495bSYour Name 	QDF_STATUS status;
500*5113495bSYour Name 	int ret;
501*5113495bSYour Name 
502*5113495bSYour Name 	hdd_enter();
503*5113495bSYour Name 
504*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
505*5113495bSYour Name 	if (ret)
506*5113495bSYour Name 		return -EINVAL;
507*5113495bSYour Name 
508*5113495bSYour Name 	if (QDF_GLOBAL_FTM_MODE == hdd_get_conparam()) {
509*5113495bSYour Name 		hdd_err_rl("Command not allowed in FTM mode");
510*5113495bSYour Name 		return -EPERM;
511*5113495bSYour Name 	}
512*5113495bSYour Name 
513*5113495bSYour Name 	if (wlan_cfg80211_nla_parse(tb,
514*5113495bSYour Name 				    QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_MAX,
515*5113495bSYour Name 				    (struct nlattr *)data, data_len,
516*5113495bSYour Name 				    wlan_hdd_thermal_mitigation_policy)) {
517*5113495bSYour Name 		hdd_err_rl("Invalid attribute");
518*5113495bSYour Name 		return -EINVAL;
519*5113495bSYour Name 	}
520*5113495bSYour Name 
521*5113495bSYour Name 	if (!tb[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE]) {
522*5113495bSYour Name 		hdd_err_rl("attr thermal cmd value failed");
523*5113495bSYour Name 		return -EINVAL;
524*5113495bSYour Name 	}
525*5113495bSYour Name 
526*5113495bSYour Name 	cmd_type = nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_VALUE]);
527*5113495bSYour Name 	switch (cmd_type) {
528*5113495bSYour Name 	case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_SET_LEVEL:
529*5113495bSYour Name 		if (!tb[QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL]) {
530*5113495bSYour Name 			hdd_err_rl("attr thermal throttle set failed");
531*5113495bSYour Name 			return -EINVAL;
532*5113495bSYour Name 		}
533*5113495bSYour Name 		level =
534*5113495bSYour Name 		    nla_get_u32(tb[QCA_WLAN_VENDOR_ATTR_THERMAL_LEVEL]);
535*5113495bSYour Name 
536*5113495bSYour Name 		hdd_debug("thermal mitigation level from userspace %d", level);
537*5113495bSYour Name 		status = hdd_send_thermal_mitigation_val(hdd_ctx, level,
538*5113495bSYour Name 							 THERMAL_MONITOR_APPS);
539*5113495bSYour Name 		ret = qdf_status_to_os_return(status);
540*5113495bSYour Name 		break;
541*5113495bSYour Name 	case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_LEVEL:
542*5113495bSYour Name 		ret = hdd_get_curr_thermal_throttle_level_val(hdd_ctx);
543*5113495bSYour Name 		break;
544*5113495bSYour Name 	case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_TEMPERATURE:
545*5113495bSYour Name 		ret = hdd_get_curr_thermal_temperature_val(hdd_ctx, adapter);
546*5113495bSYour Name 		break;
547*5113495bSYour Name 	case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_GET_THERMAL_STATS:
548*5113495bSYour Name 		ret = hdd_get_curr_thermal_stats_val(wiphy, hdd_ctx);
549*5113495bSYour Name 		break;
550*5113495bSYour Name 	case QCA_WLAN_VENDOR_ATTR_THERMAL_CMD_TYPE_CLEAR_THERMAL_STATS:
551*5113495bSYour Name 		status = hdd_send_thermal_stats_clear_cmd(hdd_ctx);
552*5113495bSYour Name 		if (QDF_IS_STATUS_ERROR(status)) {
553*5113495bSYour Name 			hdd_err("Failure while sending command to fw");
554*5113495bSYour Name 			ret = -EINVAL;
555*5113495bSYour Name 		}
556*5113495bSYour Name 		break;
557*5113495bSYour Name 	default:
558*5113495bSYour Name 		ret = -EINVAL;
559*5113495bSYour Name 	}
560*5113495bSYour Name 
561*5113495bSYour Name 	hdd_exit();
562*5113495bSYour Name 	return ret;
563*5113495bSYour Name }
564*5113495bSYour Name 
565*5113495bSYour Name /**
566*5113495bSYour Name  * wlan_hdd_cfg80211_set_thermal_mitigation_policy() - set thermal
567*5113495bSYour Name  * mitigation policy
568*5113495bSYour Name  * @wiphy: wiphy pointer
569*5113495bSYour Name  * @wdev: pointer to struct wireless_dev
570*5113495bSYour Name  * @data: pointer to incoming NL vendor data
571*5113495bSYour Name  * @data_len: length of @data
572*5113495bSYour Name  *
573*5113495bSYour Name  * Return: 0 on success; error number otherwise.
574*5113495bSYour Name  */
575*5113495bSYour Name int
wlan_hdd_cfg80211_set_thermal_mitigation_policy(struct wiphy * wiphy,struct wireless_dev * wdev,const void * data,int data_len)576*5113495bSYour Name wlan_hdd_cfg80211_set_thermal_mitigation_policy(struct wiphy *wiphy,
577*5113495bSYour Name 						struct wireless_dev *wdev,
578*5113495bSYour Name 						const void *data, int data_len)
579*5113495bSYour Name {
580*5113495bSYour Name 	struct osif_psoc_sync *psoc_sync;
581*5113495bSYour Name 	int errno;
582*5113495bSYour Name 
583*5113495bSYour Name 	errno = osif_psoc_sync_op_start(wiphy_dev(wiphy), &psoc_sync);
584*5113495bSYour Name 	if (errno)
585*5113495bSYour Name 		return errno;
586*5113495bSYour Name 
587*5113495bSYour Name 	errno = __wlan_hdd_cfg80211_set_thermal_mitigation_policy(wiphy, wdev,
588*5113495bSYour Name 								  data,
589*5113495bSYour Name 								  data_len);
590*5113495bSYour Name 
591*5113495bSYour Name 	osif_psoc_sync_op_stop(psoc_sync);
592*5113495bSYour Name 
593*5113495bSYour Name 	return errno;
594*5113495bSYour Name }
595*5113495bSYour Name 
wlan_hdd_thermal_config_support(void)596*5113495bSYour Name bool wlan_hdd_thermal_config_support(void)
597*5113495bSYour Name {
598*5113495bSYour Name 	return true;
599*5113495bSYour Name }
600*5113495bSYour Name 
hdd_restore_thermal_mitigation_config(struct hdd_context * hdd_ctx)601*5113495bSYour Name QDF_STATUS hdd_restore_thermal_mitigation_config(struct hdd_context *hdd_ctx)
602*5113495bSYour Name {
603*5113495bSYour Name 	bool enable = true;
604*5113495bSYour Name 	uint32_t dc, dc_off_percent = 0;
605*5113495bSYour Name 	uint32_t prio = 0, target_temp = 0;
606*5113495bSYour Name 	struct wlan_fwol_thermal_temp thermal_temp = {0};
607*5113495bSYour Name 	QDF_STATUS status;
608*5113495bSYour Name 	struct thermal_mitigation_params therm_cfg_params = {0};
609*5113495bSYour Name 
610*5113495bSYour Name 	status = ucfg_fwol_get_thermal_temp(hdd_ctx->psoc, &thermal_temp);
611*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status)) {
612*5113495bSYour Name 		hdd_err_rl("Failed to get fwol thermal obj");
613*5113495bSYour Name 		return status;
614*5113495bSYour Name 	}
615*5113495bSYour Name 
616*5113495bSYour Name 	dc_off_percent = hdd_ctx->dutycycle_off_percent;
617*5113495bSYour Name 	dc = thermal_temp.thermal_sampling_time;
618*5113495bSYour Name 
619*5113495bSYour Name 	if (!dc_off_percent)
620*5113495bSYour Name 		enable = false;
621*5113495bSYour Name 
622*5113495bSYour Name 	therm_cfg_params.enable = enable;
623*5113495bSYour Name 	therm_cfg_params.dc = dc;
624*5113495bSYour Name 	therm_cfg_params.levelconf[0].dcoffpercent = dc_off_percent;
625*5113495bSYour Name 	therm_cfg_params.levelconf[0].priority = prio;
626*5113495bSYour Name 	therm_cfg_params.levelconf[0].tmplwm = target_temp;
627*5113495bSYour Name 	therm_cfg_params.num_thermal_conf = 1;
628*5113495bSYour Name 	therm_cfg_params.client_id = THERMAL_MONITOR_APPS;
629*5113495bSYour Name 	therm_cfg_params.priority = 0;
630*5113495bSYour Name 
631*5113495bSYour Name 	hdd_debug("dc %d dc_off_per %d enable %d", dc, dc_off_percent, enable);
632*5113495bSYour Name 
633*5113495bSYour Name 	status = sme_set_thermal_throttle_cfg(hdd_ctx->mac_handle,
634*5113495bSYour Name 					      &therm_cfg_params);
635*5113495bSYour Name 	if (QDF_IS_STATUS_ERROR(status))
636*5113495bSYour Name 		hdd_err_rl("Failed to set throttle configuration %d", status);
637*5113495bSYour Name 
638*5113495bSYour Name 	return status;
639*5113495bSYour Name }
640*5113495bSYour Name 
641*5113495bSYour Name static int
__wlan_hdd_pld_set_thermal_mitigation(struct device * dev,unsigned long state,int mon_id)642*5113495bSYour Name __wlan_hdd_pld_set_thermal_mitigation(struct device *dev, unsigned long state,
643*5113495bSYour Name 				      int mon_id)
644*5113495bSYour Name {
645*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
646*5113495bSYour Name 	QDF_STATUS status;
647*5113495bSYour Name 	int ret;
648*5113495bSYour Name 
649*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
650*5113495bSYour Name 	if (ret)
651*5113495bSYour Name 		return ret;
652*5113495bSYour Name 
653*5113495bSYour Name 	if (hdd_ctx->driver_status == DRIVER_MODULES_CLOSED)
654*5113495bSYour Name 		return -EINVAL;
655*5113495bSYour Name 
656*5113495bSYour Name 	status = hdd_send_thermal_mitigation_val(hdd_ctx, state, mon_id);
657*5113495bSYour Name 
658*5113495bSYour Name 	return qdf_status_to_os_return(status);
659*5113495bSYour Name }
660*5113495bSYour Name 
wlan_hdd_pld_set_thermal_mitigation(struct device * dev,unsigned long state,int mon_id)661*5113495bSYour Name int wlan_hdd_pld_set_thermal_mitigation(struct device *dev, unsigned long state,
662*5113495bSYour Name 					int mon_id)
663*5113495bSYour Name {
664*5113495bSYour Name 	struct osif_psoc_sync *psoc_sync;
665*5113495bSYour Name 	int ret;
666*5113495bSYour Name 
667*5113495bSYour Name 	hdd_enter();
668*5113495bSYour Name 
669*5113495bSYour Name 	ret = osif_psoc_sync_op_start(dev, &psoc_sync);
670*5113495bSYour Name 	if (ret)
671*5113495bSYour Name 		return ret;
672*5113495bSYour Name 
673*5113495bSYour Name 	ret =  __wlan_hdd_pld_set_thermal_mitigation(dev, state, mon_id);
674*5113495bSYour Name 
675*5113495bSYour Name 	osif_psoc_sync_op_stop(psoc_sync);
676*5113495bSYour Name 	hdd_exit();
677*5113495bSYour Name 
678*5113495bSYour Name 	return ret;
679*5113495bSYour Name }
680*5113495bSYour Name 
681*5113495bSYour Name #ifdef FEATURE_WPSS_THERMAL_MITIGATION
hdd_thermal_mitigation_register_wpps(struct hdd_context * hdd_ctx,struct device * dev)682*5113495bSYour Name inline void hdd_thermal_mitigation_register_wpps(struct hdd_context *hdd_ctx,
683*5113495bSYour Name 						 struct device *dev)
684*5113495bSYour Name {
685*5113495bSYour Name 	if (hdd_ctx->multi_client_thermal_mitigation)
686*5113495bSYour Name 		pld_thermal_register(dev, HDD_THERMAL_STATE_LIGHT,
687*5113495bSYour Name 				     THERMAL_MONITOR_WPSS);
688*5113495bSYour Name }
689*5113495bSYour Name 
hdd_thermal_mitigation_unregister_wpps(struct hdd_context * hdd_ctx,struct device * dev)690*5113495bSYour Name inline void hdd_thermal_mitigation_unregister_wpps(struct hdd_context *hdd_ctx,
691*5113495bSYour Name 						   struct device *dev)
692*5113495bSYour Name {
693*5113495bSYour Name 	if (hdd_ctx->multi_client_thermal_mitigation)
694*5113495bSYour Name 		pld_thermal_unregister(dev, THERMAL_MONITOR_WPSS);
695*5113495bSYour Name }
696*5113495bSYour Name #else
697*5113495bSYour Name static inline
hdd_thermal_mitigation_register_wpps(struct hdd_context * hdd_ctx,struct device * dev)698*5113495bSYour Name void hdd_thermal_mitigation_register_wpps(struct hdd_context *hdd_ctx,
699*5113495bSYour Name 					  struct device *dev)
700*5113495bSYour Name {
701*5113495bSYour Name }
702*5113495bSYour Name 
703*5113495bSYour Name static inline
hdd_thermal_mitigation_unregister_wpps(struct hdd_context * hdd_ctx,struct device * dev)704*5113495bSYour Name void hdd_thermal_mitigation_unregister_wpps(struct hdd_context *hdd_ctx,
705*5113495bSYour Name 					    struct device *dev)
706*5113495bSYour Name {
707*5113495bSYour Name }
708*5113495bSYour Name #endif
hdd_thermal_mitigation_register(struct hdd_context * hdd_ctx,struct device * dev)709*5113495bSYour Name void hdd_thermal_mitigation_register(struct hdd_context *hdd_ctx,
710*5113495bSYour Name 				     struct device *dev)
711*5113495bSYour Name {
712*5113495bSYour Name 	pld_thermal_register(dev, HDD_THERMAL_STATE_EMERGENCY,
713*5113495bSYour Name 			     THERMAL_MONITOR_APPS);
714*5113495bSYour Name 	hdd_thermal_mitigation_register_wpps(hdd_ctx, dev);
715*5113495bSYour Name }
716*5113495bSYour Name 
hdd_thermal_mitigation_unregister(struct hdd_context * hdd_ctx,struct device * dev)717*5113495bSYour Name void hdd_thermal_mitigation_unregister(struct hdd_context *hdd_ctx,
718*5113495bSYour Name 				       struct device *dev)
719*5113495bSYour Name {
720*5113495bSYour Name 	hdd_thermal_mitigation_unregister_wpps(hdd_ctx, dev);
721*5113495bSYour Name 	pld_thermal_unregister(dev, THERMAL_MONITOR_APPS);
722*5113495bSYour Name }
723*5113495bSYour Name 
724*5113495bSYour Name #ifdef FW_THERMAL_THROTTLE_SUPPORT
725*5113495bSYour Name /**
726*5113495bSYour Name  * hdd_notify_thermal_throttle_handler() - Thermal throttle event handler
727*5113495bSYour Name  * @psoc: psoc object
728*5113495bSYour Name  * @info: thermal throttle information from target
729*5113495bSYour Name  *
730*5113495bSYour Name  * Return: QDF_STATUS_SUCCESS for success.
731*5113495bSYour Name  */
732*5113495bSYour Name static QDF_STATUS
hdd_notify_thermal_throttle_handler(struct wlan_objmgr_psoc * psoc,struct thermal_throttle_info * info)733*5113495bSYour Name hdd_notify_thermal_throttle_handler(struct wlan_objmgr_psoc *psoc,
734*5113495bSYour Name 				    struct thermal_throttle_info *info)
735*5113495bSYour Name {
736*5113495bSYour Name 	uint32_t data_len;
737*5113495bSYour Name 	struct sk_buff *vendor_event;
738*5113495bSYour Name 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
739*5113495bSYour Name 	int ret;
740*5113495bSYour Name 	enum qca_wlan_vendor_thermal_level level;
741*5113495bSYour Name 
742*5113495bSYour Name 	ret = wlan_hdd_validate_context(hdd_ctx);
743*5113495bSYour Name 	if (ret)
744*5113495bSYour Name 		return QDF_STATUS_E_FAILURE;
745*5113495bSYour Name 
746*5113495bSYour Name 	/* TX will be throttled completely if above MITIGATION level.
747*5113495bSYour Name 	 * So report additional DIAG event to notify user-space explicitly.
748*5113495bSYour Name 	 */
749*5113495bSYour Name 	if (info->level == THERMAL_SHUTOFF ||
750*5113495bSYour Name 	    info->level == THERMAL_SHUTDOWN_TARGET)
751*5113495bSYour Name 		host_log_device_status(WLAN_STATUS_DEVICE_TEMPERATURE_HIGH);
752*5113495bSYour Name 
753*5113495bSYour Name 	data_len = NLMSG_HDRLEN + nla_total_size(sizeof(uint32_t));
754*5113495bSYour Name 	vendor_event = wlan_cfg80211_vendor_event_alloc(
755*5113495bSYour Name 				hdd_ctx->wiphy, NULL, data_len,
756*5113495bSYour Name 				QCA_NL80211_VENDOR_SUBCMD_THERMAL_INDEX,
757*5113495bSYour Name 				GFP_KERNEL);
758*5113495bSYour Name 	if (!vendor_event) {
759*5113495bSYour Name 		hdd_err("wlan_cfg80211_vendor_event_alloc failed");
760*5113495bSYour Name 		return QDF_STATUS_E_NOMEM;
761*5113495bSYour Name 	}
762*5113495bSYour Name 	level = convert_level_to_vendor_thermal_level(info->level);
763*5113495bSYour Name 	if (nla_put_u32(vendor_event,
764*5113495bSYour Name 			QCA_WLAN_VENDOR_ATTR_THERMAL_EVENT_LEVEL,
765*5113495bSYour Name 			level)) {
766*5113495bSYour Name 		wlan_cfg80211_vendor_free_skb(vendor_event);
767*5113495bSYour Name 		return QDF_STATUS_E_INVAL;
768*5113495bSYour Name 	}
769*5113495bSYour Name 	hdd_debug("thermal_throttle:level %d vendor level %d", info->level,
770*5113495bSYour Name 		  level);
771*5113495bSYour Name 	wlan_cfg80211_vendor_event(vendor_event, GFP_KERNEL);
772*5113495bSYour Name 
773*5113495bSYour Name 	return QDF_STATUS_SUCCESS;
774*5113495bSYour Name }
775*5113495bSYour Name 
hdd_thermal_register_callbacks(struct hdd_context * hdd_ctx)776*5113495bSYour Name void hdd_thermal_register_callbacks(struct hdd_context *hdd_ctx)
777*5113495bSYour Name {
778*5113495bSYour Name 	struct fwol_thermal_callbacks cb_obj = {0};
779*5113495bSYour Name 
780*5113495bSYour Name 	cb_obj.notify_thermal_throttle_handler =
781*5113495bSYour Name 		hdd_notify_thermal_throttle_handler;
782*5113495bSYour Name 	ucfg_fwol_thermal_register_callbacks(hdd_ctx->psoc, &cb_obj);
783*5113495bSYour Name }
784*5113495bSYour Name 
hdd_thermal_unregister_callbacks(struct hdd_context * hdd_ctx)785*5113495bSYour Name void hdd_thermal_unregister_callbacks(struct hdd_context *hdd_ctx)
786*5113495bSYour Name {
787*5113495bSYour Name 	ucfg_fwol_thermal_unregister_callbacks(hdd_ctx->psoc);
788*5113495bSYour Name }
789*5113495bSYour Name #endif
790