1 /*
2  * Copyright (c) 2011-2020 The Linux Foundation. All rights reserved.
3  * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /**
19  * DOC: wlan_hdd_sysfs_thermal_cfg.c
20  *
21  * implementation for creating sysfs file thermal_cfg
22  */
23 
24 #include <wlan_hdd_includes.h>
25 #include "osif_psoc_sync.h"
26 #include <wlan_hdd_sysfs.h>
27 #include <wlan_hdd_sysfs_thermal_cfg.h>
28 #include "qdf_trace.h"
29 #include "sme_api.h"
30 #include "qdf_status.h"
31 #include <wlan_fw_offload_main.h>
32 #include "wlan_hdd_thermal.h"
33 #include <wlan_fwol_ucfg_api.h>
34 
35 #ifdef FW_THERMAL_THROTTLE_SUPPORT
36 #ifndef QCN7605_SUPPORT
hdd_send_thermal_mgmt_cmd(mac_handle_t mac_handle,uint16_t lower_thresh_deg,uint16_t higher_thresh_deg)37 static QDF_STATUS hdd_send_thermal_mgmt_cmd(mac_handle_t mac_handle,
38 					    uint16_t lower_thresh_deg,
39 					    uint16_t higher_thresh_deg)
40 {
41 	return sme_set_thermal_mgmt(mac_handle, lower_thresh_deg,
42 				    higher_thresh_deg);
43 }
44 #else
hdd_send_thermal_mgmt_cmd(mac_handle_t mac_handle,uint16_t lower_thresh_deg,uint16_t higher_thresh_deg)45 static QDF_STATUS hdd_send_thermal_mgmt_cmd(mac_handle_t mac_handle,
46 					    uint16_t lower_thresh_deg,
47 					    uint16_t higher_thresh_deg)
48 {
49 	return QDF_STATUS_SUCCESS;
50 }
51 #endif
52 #endif /* FW_THERMAL_THROTTLE_SUPPORT */
53 
54 static ssize_t
__hdd_sysfs_thermal_cfg_store(struct hdd_context * hdd_ctx,struct kobj_attribute * attr,const char * buf,size_t count)55 __hdd_sysfs_thermal_cfg_store(struct hdd_context *hdd_ctx,
56 			      struct kobj_attribute *attr,
57 			      const char *buf,
58 			      size_t count)
59 {
60 	char buf_local[MAX_SYSFS_USER_COMMAND_SIZE_LENGTH + 1];
61 	char *sptr, *token;
62 	uint32_t val1, val2, val3, val4, val7;
63 	uint16_t val5, val6;
64 	QDF_STATUS status;
65 	int ret;
66 	struct thermal_mitigation_params therm_cfg_params;
67 	struct wlan_fwol_thermal_temp thermal_temp = {0};
68 
69 	status = ucfg_fwol_get_thermal_temp(hdd_ctx->psoc, &thermal_temp);
70 	if (QDF_IS_STATUS_ERROR(status)) {
71 		hdd_err_rl("Failed to get fwol thermal obj");
72 		return status;
73 	}
74 
75 	if (!wlan_hdd_validate_modules_state(hdd_ctx))
76 		return -EINVAL;
77 
78 	ret = hdd_sysfs_validate_and_copy_buf(buf_local, sizeof(buf_local),
79 					      buf, count);
80 
81 	if (ret) {
82 		hdd_err_rl("invalid input");
83 		return ret;
84 	}
85 
86 	sptr = buf_local;
87 	hdd_debug("thermal_cfg: count %zu buf_local:(%s)",
88 		  count, buf_local);
89 
90 	/* Get val1 */
91 	token = strsep(&sptr, " ");
92 	if (!token)
93 		return -EINVAL;
94 	if (kstrtou32(token, 0, &val1))
95 		return -EINVAL;
96 
97 	/* Get val2 */
98 	token = strsep(&sptr, " ");
99 	if (!token)
100 		return -EINVAL;
101 	if (kstrtou32(token, 0, &val2))
102 		return -EINVAL;
103 
104 	/* Get val3 */
105 	token = strsep(&sptr, " ");
106 	if (!token)
107 		return -EINVAL;
108 	if (kstrtou32(token, 0, &val3))
109 		return -EINVAL;
110 
111 	/* Get val4 */
112 	token = strsep(&sptr, " ");
113 	if (!token)
114 		return -EINVAL;
115 	if (kstrtou32(token, 0, &val4))
116 		return -EINVAL;
117 
118 	/* Get val5 */
119 	token = strsep(&sptr, " ");
120 	if (!token)
121 		return -EINVAL;
122 	if (kstrtou16(token, 0, &val5))
123 		return -EINVAL;
124 
125 	/* Get val6 */
126 	token = strsep(&sptr, " ");
127 	if (!token)
128 		return -EINVAL;
129 	if (kstrtou16(token, 0, &val6))
130 		return -EINVAL;
131 
132 	/* Get val7 */
133 	token = strsep(&sptr, " ");
134 	if (!token)
135 		return -EINVAL;
136 	if (kstrtou32(token, 0, &val7))
137 		return -EINVAL;
138 
139 	/* Check for valid inputs */
140 	if (val1 < 0 || val1 > 1 || val2 < 0 || val3 < 0 || val3 > 100 ||
141 	    val4 < 0 || val4 > 3 ||  val5 < 0 || val6 < 0 || val7 < 0 ||
142 	    val6 <= val5)
143 		return -EINVAL;
144 
145 	therm_cfg_params.enable = val1;
146 	therm_cfg_params.dc = val2;
147 	therm_cfg_params.levelconf[0].dcoffpercent = val3;
148 	therm_cfg_params.levelconf[0].priority = val4;
149 	therm_cfg_params.levelconf[0].tmplwm = val7;
150 	hdd_thermal_fill_clientid_priority(hdd_ctx, THERMAL_MONITOR_APPS,
151 					   thermal_temp.priority_apps,
152 					   thermal_temp.priority_wpps,
153 					   &therm_cfg_params);
154 
155 	status = sme_set_thermal_throttle_cfg(hdd_ctx->mac_handle,
156 					      &therm_cfg_params);
157 
158 	if (QDF_IS_STATUS_ERROR(status))
159 		return qdf_status_to_os_return(status);
160 
161 	if (!val7) {
162 		status = hdd_send_thermal_mgmt_cmd(hdd_ctx->mac_handle,
163 						   val5, val6);
164 
165 		if (QDF_IS_STATUS_ERROR(status))
166 			return qdf_status_to_os_return(status);
167 	}
168 
169 	return count;
170 }
171 
172 static ssize_t
hdd_sysfs_thermal_cfg_store(struct kobject * kobj,struct kobj_attribute * attr,const char * buf,size_t count)173 hdd_sysfs_thermal_cfg_store(struct kobject *kobj,
174 			    struct kobj_attribute *attr,
175 			    const char *buf,
176 			    size_t count)
177 {
178 	struct osif_psoc_sync *psoc_sync;
179 	struct hdd_context *hdd_ctx = cds_get_context(QDF_MODULE_ID_HDD);
180 	ssize_t errno_size;
181 	int ret;
182 
183 	ret = wlan_hdd_validate_context(hdd_ctx);
184 	if (ret != 0)
185 		return ret;
186 
187 	errno_size = osif_psoc_sync_op_start(wiphy_dev(hdd_ctx->wiphy),
188 					     &psoc_sync);
189 	if (errno_size)
190 		return errno_size;
191 
192 	errno_size = __hdd_sysfs_thermal_cfg_store(hdd_ctx, attr,
193 						   buf, count);
194 
195 	osif_psoc_sync_op_stop(psoc_sync);
196 
197 	return errno_size;
198 }
199 
200 static struct kobj_attribute thermal_cfg_attribute =
201 	__ATTR(thermal_cfg, 0220, NULL,
202 	       hdd_sysfs_thermal_cfg_store);
203 
hdd_sysfs_thermal_cfg_create(struct kobject * driver_kobject)204 int hdd_sysfs_thermal_cfg_create(struct kobject *driver_kobject)
205 {
206 	int error;
207 
208 	if (!driver_kobject) {
209 		hdd_err("could not get driver kobject!");
210 		return -EINVAL;
211 	}
212 
213 	error = sysfs_create_file(driver_kobject,
214 				  &thermal_cfg_attribute.attr);
215 	if (error)
216 		hdd_err("could not create thermal_cfg sysfs file");
217 
218 	return error;
219 }
220 
221 void
hdd_sysfs_thermal_cfg_destroy(struct kobject * driver_kobject)222 hdd_sysfs_thermal_cfg_destroy(struct kobject *driver_kobject)
223 {
224 	if (!driver_kobject) {
225 		hdd_err("could not get driver kobject!");
226 		return;
227 	}
228 	sysfs_remove_file(driver_kobject, &thermal_cfg_attribute.attr);
229 }
230