Commit | Line | Data |
---|---|---|
6fa3eb70 S |
1 | /* |
2 | * Copyright (C) 2011-2014 MediaTek Inc. | |
3 | * | |
4 | * This program is free software: you can redistribute it and/or modify it under the terms of the | |
5 | * GNU General Public License version 2 as published by the Free Software Foundation. | |
6 | * | |
7 | * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; | |
8 | * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. | |
9 | * See the GNU General Public License for more details. | |
10 | * | |
11 | * You should have received a copy of the GNU General Public License along with this program. | |
12 | * If not, see <http://www.gnu.org/licenses/>. | |
13 | */ | |
14 | ||
15 | #ifdef pr_fmt | |
16 | #undef pr_fmt | |
17 | #endif | |
18 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
19 | ||
20 | #include <linux/version.h> | |
21 | #include <linux/thermal.h> | |
22 | #include <linux/printk.h> | |
23 | #include <linux/proc_fs.h> | |
24 | #include <linux/seq_file.h> | |
25 | #include <asm/uaccess.h> | |
26 | /* #include "wmt_tm.h" */ | |
27 | #include <mach/mtk_thermal_monitor.h> | |
28 | #include <linux/timer.h> | |
29 | #include <linux/pid.h> | |
30 | /* For using net dev + */ | |
31 | #include <linux/netdevice.h> | |
32 | /* For using net dev - */ | |
33 | #include <mach/mtk_wcn_cmb_stub.h> | |
34 | ||
35 | ||
36 | static int wmt_tm_debug_log = 0; | |
37 | #define wmt_tm_dprintk(fmt, args...) \ | |
38 | do { \ | |
39 | if (wmt_tm_debug_log) { \ | |
40 | pr_debug("tz/mtktswmt " fmt, ##args); \ | |
41 | } \ | |
42 | } while(0) | |
43 | ||
44 | #define wmt_tm_printk(fmt, args...) \ | |
45 | do { \ | |
46 | pr_debug("tz/mtktswmt " fmt, ##args); \ | |
47 | } while(0) | |
48 | ||
49 | #define wmt_tm_info(fmt, args...) \ | |
50 | do { \ | |
51 | pr_debug("tz/mtktswmt " fmt, ##args); \ | |
52 | } while(0) | |
53 | ||
54 | struct linux_thermal_ctrl_if { | |
55 | int kernel_mode; | |
56 | int interval; | |
57 | struct thermal_zone_device *thz_dev; | |
58 | struct thermal_cooling_device *cl_dev; | |
59 | struct thermal_cooling_device *cl_pa1_dev; | |
60 | struct thermal_cooling_device *cl_pa2_dev; | |
61 | struct thermal_cooling_device *cl_pa3_dev; | |
62 | }; | |
63 | ||
64 | #if 0 | |
65 | struct wmt_thermal_ctrl_if { | |
66 | struct wmt_thermal_ctrl_ops ops; | |
67 | }; | |
68 | #endif | |
69 | ||
70 | typedef struct wmt_tm { | |
71 | struct linux_thermal_ctrl_if linux_if; | |
72 | /* struct wmt_thermal_ctrl_if wmt_if; */ | |
73 | }wmt_tm_t; | |
74 | ||
75 | struct wmt_stats { | |
76 | unsigned long pre_time; | |
77 | unsigned long pre_tx_bytes; | |
78 | }; | |
79 | ||
80 | extern struct proc_dir_entry * mtk_thermal_get_proc_drv_therm_dir_entry(void); | |
81 | ||
82 | static struct timer_list wmt_stats_timer; | |
83 | static struct wmt_stats wmt_stats_info; | |
84 | static unsigned long pre_time; | |
85 | static unsigned long tx_throughput; | |
86 | ||
87 | /*New Wifi throttling Algo+*/ | |
88 | //over_up_time * polling interval > up_duration --> throttling | |
89 | static unsigned int over_up_time = 0; //polling time | |
90 | static unsigned int up_duration = 30; //sec | |
91 | static unsigned int up_denominator = 2; | |
92 | static unsigned int up_numerator = 1; | |
93 | ||
94 | //below_low_time * polling interval > low_duration --> throttling | |
95 | static unsigned int below_low_time = 0; //polling time | |
96 | static unsigned int low_duration = 10; //sec | |
97 | static unsigned int low_denominator = 2; | |
98 | static unsigned int low_numerator = 3; | |
99 | ||
100 | static unsigned int low_rst_time = 0; | |
101 | static unsigned int low_rst_max = 3; | |
102 | /*New Wifi throttling Algo-*/ | |
103 | ||
104 | #define MAX_LEN 256 | |
105 | #define COOLER_THRO_NUM 3 | |
106 | #define COOLER_NUM 10 | |
107 | #define ONE_MBITS_PER_SEC 1000 | |
108 | ||
109 | static unsigned int tm_pid = 0; | |
110 | static unsigned int tm_input_pid = 0; | |
111 | static unsigned int tm_wfd_stat = 0; | |
112 | static struct task_struct g_task; | |
113 | static struct task_struct *pg_task = &g_task; | |
114 | ||
115 | /* +Cooler info+ */ | |
116 | static int g_num_trip = COOLER_THRO_NUM + 1; | |
117 | static char g_bind0[20]="mtktswmt-pa1"; | |
118 | static char g_bind1[20]="mtktswmt-pa2"; | |
119 | static char g_bind2[20]="mtktswmt-pa3"; | |
120 | static char g_bind3[20]="mtktswmt-sysrst"; | |
121 | static char g_bind4[20]={0}; | |
122 | static char g_bind5[20]={0}; | |
123 | static char g_bind6[20]={0}; | |
124 | static char g_bind7[20]={0}; | |
125 | static char g_bind8[20]={0}; | |
126 | static char g_bind9[20]={0}; | |
127 | ||
128 | /** | |
129 | * If curr_temp >= polling_trip_temp1, use interval | |
130 | * else if cur_temp >= polling_trip_temp2 && curr_temp < polling_trip_temp1, use interval*polling_factor1 | |
131 | * else, use interval*polling_factor2 | |
132 | */ | |
133 | static int polling_trip_temp1 = 40000; | |
134 | static int polling_trip_temp2 = 20000; | |
135 | static int polling_factor1 = 5; | |
136 | static int polling_factor2 = 10; | |
137 | ||
138 | static unsigned int cl_dev_state =0; | |
139 | static unsigned int cl_pa1_dev_state =0; | |
140 | static unsigned int cl_pa2_dev_state =0; | |
141 | /*static unsigned int cl_pa3_dev_state =0;*/ | |
142 | static unsigned int g_trip_temp[COOLER_NUM] = {85000,85000,85000,85000,0,0,0,0,0,0}; | |
143 | ||
144 | /*static int g_thro[COOLER_THRO_NUM] = {10 * ONE_MBITS_PER_SEC, 5 * ONE_MBITS_PER_SEC, 1 * ONE_MBITS_PER_SEC};*/ | |
145 | static int g_thermal_trip[COOLER_NUM] = {0,0,0,0,0,0,0,0,0,0}; | |
146 | ||
147 | /* -Cooler info- */ | |
148 | ||
149 | wmt_tm_t g_wmt_tm; | |
150 | wmt_tm_t *pg_wmt_tm = &g_wmt_tm; | |
151 | ||
152 | static int wmt_thz_bind(struct thermal_zone_device *, | |
153 | struct thermal_cooling_device *); | |
154 | static int wmt_thz_unbind(struct thermal_zone_device *, | |
155 | struct thermal_cooling_device *); | |
156 | static int wmt_thz_get_temp(struct thermal_zone_device *, | |
157 | unsigned long *); | |
158 | static int wmt_thz_get_mode(struct thermal_zone_device *, | |
159 | enum thermal_device_mode *); | |
160 | static int wmt_thz_set_mode(struct thermal_zone_device *, | |
161 | enum thermal_device_mode); | |
162 | static int wmt_thz_get_trip_type(struct thermal_zone_device *, int, | |
163 | enum thermal_trip_type *); | |
164 | static int wmt_thz_get_trip_temp(struct thermal_zone_device *, int, | |
165 | unsigned long *); | |
166 | static int wmt_thz_get_crit_temp(struct thermal_zone_device *, | |
167 | unsigned long *); | |
168 | static int wmt_cl_get_max_state(struct thermal_cooling_device *, | |
169 | unsigned long *); | |
170 | static int wmt_cl_get_cur_state(struct thermal_cooling_device *, | |
171 | unsigned long *); | |
172 | static int wmt_cl_set_cur_state(struct thermal_cooling_device *, | |
173 | unsigned long); | |
174 | ||
175 | static int wmt_cl_pa1_get_max_state(struct thermal_cooling_device *, | |
176 | unsigned long *); | |
177 | static int wmt_cl_pa1_get_cur_state(struct thermal_cooling_device *, | |
178 | unsigned long *); | |
179 | static int wmt_cl_pa1_set_cur_state(struct thermal_cooling_device *, | |
180 | unsigned long); | |
181 | ||
182 | static int wmt_cl_pa2_get_max_state(struct thermal_cooling_device *, | |
183 | unsigned long *); | |
184 | static int wmt_cl_pa2_get_cur_state(struct thermal_cooling_device *, | |
185 | unsigned long *); | |
186 | static int wmt_cl_pa2_set_cur_state(struct thermal_cooling_device *, | |
187 | unsigned long); | |
188 | ||
189 | #ifdef NEVER | |
190 | static int wmt_cl_pa3_get_max_state(struct thermal_cooling_device *, | |
191 | unsigned long *); | |
192 | static int wmt_cl_pa3_get_cur_state(struct thermal_cooling_device *, | |
193 | unsigned long *); | |
194 | static int wmt_cl_pa3_set_cur_state(struct thermal_cooling_device *, | |
195 | unsigned long); | |
196 | #endif /* NEVER */ | |
197 | ||
198 | static struct thermal_zone_device_ops wmt_thz_dev_ops = { | |
199 | .bind = wmt_thz_bind, | |
200 | .unbind = wmt_thz_unbind, | |
201 | .get_temp = wmt_thz_get_temp, | |
202 | .get_mode = wmt_thz_get_mode, | |
203 | .set_mode = wmt_thz_set_mode, | |
204 | .get_trip_type = wmt_thz_get_trip_type, | |
205 | .get_trip_temp = wmt_thz_get_trip_temp, | |
206 | .get_crit_temp = wmt_thz_get_crit_temp, | |
207 | }; | |
208 | ||
209 | static struct thermal_cooling_device_ops mtktspa_cooling_sysrst_ops = { | |
210 | .get_max_state = wmt_cl_get_max_state, | |
211 | .get_cur_state = wmt_cl_get_cur_state, | |
212 | .set_cur_state = wmt_cl_set_cur_state, | |
213 | }; | |
214 | ||
215 | static struct thermal_cooling_device_ops mtktspa_cooling_pa1_ops = { | |
216 | .get_max_state = wmt_cl_pa1_get_max_state, | |
217 | .get_cur_state = wmt_cl_pa1_get_cur_state, | |
218 | .set_cur_state = wmt_cl_pa1_set_cur_state, | |
219 | }; | |
220 | ||
221 | static struct thermal_cooling_device_ops mtktspa_cooling_pa2_ops = { | |
222 | .get_max_state = wmt_cl_pa2_get_max_state, | |
223 | .get_cur_state = wmt_cl_pa2_get_cur_state, | |
224 | .set_cur_state = wmt_cl_pa2_set_cur_state, | |
225 | }; | |
226 | ||
227 | #ifdef NEVER | |
228 | static struct thermal_cooling_device_ops mtktspa_cooling_pa3_ops = { | |
229 | .get_max_state = wmt_cl_pa3_get_max_state, | |
230 | .get_cur_state = wmt_cl_pa3_get_cur_state, | |
231 | .set_cur_state = wmt_cl_pa3_set_cur_state, | |
232 | }; | |
233 | #endif /* NEVER */ | |
234 | ||
235 | static unsigned long get_tx_bytes(void) | |
236 | { | |
237 | struct net_device *dev; | |
238 | struct net *net; | |
239 | unsigned long tx_bytes = 0; | |
240 | ||
241 | read_lock(&dev_base_lock); | |
242 | for_each_net(net) { | |
243 | for_each_netdev(net, dev) { | |
244 | if(!strncmp(dev->name, "wlan", 4) || !strncmp(dev->name, "ap", 2) || !strncmp(dev->name, "p2p", 3)) { | |
245 | struct rtnl_link_stats64 temp; | |
246 | const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp); | |
247 | tx_bytes = tx_bytes + stats->tx_bytes; | |
248 | } | |
249 | } | |
250 | } | |
251 | read_unlock(&dev_base_lock); | |
252 | return tx_bytes; | |
253 | } | |
254 | ||
255 | static int wmt_cal_stats(unsigned long data) | |
256 | { | |
257 | struct wmt_stats *stats_info = (struct wmt_stats*) data; | |
258 | struct timeval cur_time; | |
259 | ||
260 | wmt_tm_dprintk("[%s] pre_time=%lu, pre_data=%lu\n", __func__, pre_time, stats_info->pre_tx_bytes); | |
261 | ||
262 | do_gettimeofday(&cur_time); | |
263 | ||
264 | if (pre_time != 0 && cur_time.tv_sec > pre_time) { | |
265 | unsigned long tx_bytes = get_tx_bytes(); | |
266 | if (tx_bytes > stats_info->pre_tx_bytes) { | |
267 | ||
268 | tx_throughput = ((tx_bytes - stats_info->pre_tx_bytes) / (cur_time.tv_sec - pre_time)) >> 7; | |
269 | ||
270 | wmt_tm_dprintk("[%s] cur_time=%lu, cur_data=%lu, tx_throughput=%luKb/s\n", __func__, cur_time.tv_sec, tx_bytes, tx_throughput ); | |
271 | ||
272 | stats_info->pre_tx_bytes = tx_bytes; | |
273 | } else if (tx_bytes < stats_info->pre_tx_bytes) { | |
274 | /* Overflow */ | |
275 | tx_throughput = ((0xffffffff - stats_info->pre_tx_bytes + tx_bytes) / (cur_time.tv_sec - pre_time)) >> 7;; | |
276 | stats_info->pre_tx_bytes = tx_bytes; | |
277 | wmt_tm_dprintk("[%s] cur_tx(%lu) < pre_tx\n", __func__, tx_bytes); | |
278 | } else { | |
279 | /* No traffic */ | |
280 | tx_throughput = 0; | |
281 | wmt_tm_dprintk("[%s] cur_tx(%lu) = pre_tx\n", __func__, tx_bytes); | |
282 | } | |
283 | } else { | |
284 | /* Overflow possible ??*/ | |
285 | tx_throughput = 0; | |
286 | wmt_tm_printk("[%s] cur_time(%lu) < pre_time\n", __func__, cur_time.tv_sec); | |
287 | } | |
288 | ||
289 | pre_time = cur_time.tv_sec; | |
290 | wmt_tm_dprintk("[%s] pre_time=%lu, tv_sec=%lu\n",__func__, pre_time, cur_time.tv_sec); | |
291 | ||
292 | wmt_stats_timer.expires = jiffies + 1 * HZ; | |
293 | add_timer(&wmt_stats_timer); | |
294 | return 0; | |
295 | } | |
296 | ||
297 | static int wmt_thz_bind(struct thermal_zone_device *thz_dev, | |
298 | struct thermal_cooling_device *cool_dev) | |
299 | { | |
300 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
301 | int table_val = 0; | |
302 | ||
303 | wmt_tm_dprintk("[%s]\n", __func__); | |
304 | ||
305 | if (pg_wmt_tm) { | |
306 | p_linux_if = &pg_wmt_tm->linux_if; | |
307 | } else { | |
308 | return -EINVAL; | |
309 | } | |
310 | #ifdef NEVER | |
311 | /* cooling devices */ | |
312 | if (cool_dev != p_linux_if->cl_dev) { | |
313 | return 0; | |
314 | } | |
315 | #endif | |
316 | ||
317 | if(!strcmp(cool_dev->type, g_bind0)) { | |
318 | table_val = 0; | |
319 | wmt_tm_dprintk("[%s] %s\n", __func__, cool_dev->type); | |
320 | } else if(!strcmp(cool_dev->type, g_bind1)) { | |
321 | table_val = 1; | |
322 | wmt_tm_dprintk("[%s] %s\n", __func__, cool_dev->type); | |
323 | } else if(!strcmp(cool_dev->type, g_bind2)) { | |
324 | table_val = 2; | |
325 | wmt_tm_dprintk("[%s]] %s\n", __func__, cool_dev->type); | |
326 | } else if(!strcmp(cool_dev->type, g_bind3)) { | |
327 | table_val = 3; | |
328 | wmt_tm_dprintk("[%s]] %s\n", __func__, cool_dev->type); | |
329 | } else | |
330 | return 0; | |
331 | ||
332 | if (mtk_thermal_zone_bind_cooling_device(thz_dev, table_val, cool_dev)) { | |
333 | wmt_tm_info("[%s] binding fail\n", __func__); | |
334 | return -EINVAL; | |
335 | } else { | |
336 | wmt_tm_dprintk("[%s]] binding OK\n", __func__); | |
337 | } | |
338 | ||
339 | return 0; | |
340 | ||
341 | } | |
342 | ||
343 | static int wmt_thz_unbind(struct thermal_zone_device *thz_dev, | |
344 | struct thermal_cooling_device *cool_dev) | |
345 | { | |
346 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
347 | int table_val = 0; | |
348 | ||
349 | wmt_tm_dprintk("[wmt_thz_unbind] \n"); | |
350 | ||
351 | if (pg_wmt_tm) { | |
352 | p_linux_if = &pg_wmt_tm->linux_if; | |
353 | } else { | |
354 | return -EINVAL; | |
355 | } | |
356 | #if 0 | |
357 | /* cooling devices */ | |
358 | if (cool_dev == p_linux_if->cl_dev) { | |
359 | table_val= 0; | |
360 | } else { | |
361 | wmt_tm_dprintk("[wmt_thz_unbind] unbind device fail..!\n"); | |
362 | return -EINVAL; | |
363 | } | |
364 | #endif | |
365 | ||
366 | if(!strcmp(cool_dev->type, g_bind0)) { | |
367 | table_val = 0; | |
368 | wmt_tm_dprintk("[wmt_thz_unbind] %s\n", cool_dev->type); | |
369 | } else if(!strcmp(cool_dev->type, g_bind1)) { | |
370 | table_val = 1; | |
371 | wmt_tm_dprintk("[wmt_thz_unbind] %s\n", cool_dev->type); | |
372 | } else if(!strcmp(cool_dev->type, g_bind2)) { | |
373 | table_val = 2; | |
374 | wmt_tm_dprintk("[wmt_thz_unbind] %s\n", cool_dev->type); | |
375 | } else if(!strcmp(cool_dev->type, g_bind3)) { | |
376 | table_val = 3; | |
377 | wmt_tm_dprintk("[wmt_thz_unbind] %s\n", cool_dev->type); | |
378 | } else | |
379 | return 0; | |
380 | ||
381 | if (thermal_zone_unbind_cooling_device(thz_dev, table_val, cool_dev)) { | |
382 | wmt_tm_info("[wmt_thz_unbind] error unbinding cooling dev\n"); | |
383 | return -EINVAL; | |
384 | } else { | |
385 | wmt_tm_dprintk("[wmt_thz_unbind] unbinding OK\n"); | |
386 | } | |
387 | ||
388 | return 0; | |
389 | } | |
390 | ||
391 | static int wmt_thz_get_temp(struct thermal_zone_device *thz_dev, unsigned long *pv) | |
392 | { | |
393 | /* struct wmt_thermal_ctrl_ops *p_des; */ | |
394 | int temp = 0; | |
395 | ||
396 | *pv = 0; | |
397 | ||
398 | /* if(pg_wmt_tm) { */ | |
399 | { | |
400 | /* p_des = &pg_wmt_tm->wmt_if.ops; */ | |
401 | /* temp = p_des->query_temp(); */ | |
402 | temp = mtk_wcn_cmb_stub_query_ctrl(); | |
403 | ||
404 | if (temp >= 255) /* dummy values */ | |
405 | temp = -127; | |
406 | ||
407 | /* temp = ((temp & 0x80) == 0x0)?temp:(-1)*temp ; */ | |
408 | /* temp = ((temp & 0x80) == 0x0)?temp:(-1)*(temp & 0x7f); */ | |
409 | *pv = temp*1000; | |
410 | ||
411 | wmt_tm_dprintk("[wmt_thz_get_temp] temp = %d\n", temp); | |
412 | ||
413 | if (temp != -127) { | |
414 | if(temp > 100 || temp < -30) | |
415 | wmt_tm_info("[wmt_thz_get_temp] temp = %d\n", temp); | |
416 | } | |
417 | } | |
418 | ||
419 | if ((int)*pv >= polling_trip_temp1) | |
420 | thz_dev->polling_delay = g_wmt_tm.linux_if.interval; | |
421 | else if ((int)*pv < polling_trip_temp2) | |
422 | thz_dev->polling_delay = g_wmt_tm.linux_if.interval * polling_factor2; | |
423 | else | |
424 | thz_dev->polling_delay = g_wmt_tm.linux_if.interval * polling_factor1; | |
425 | ||
426 | return 0; | |
427 | } | |
428 | ||
429 | static int wmt_thz_get_mode(struct thermal_zone_device *thz_dev, enum thermal_device_mode *mode) | |
430 | { | |
431 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
432 | /* int kernel_mode = 0; */ | |
433 | ||
434 | wmt_tm_dprintk("[%s]\n", __func__); | |
435 | ||
436 | if (pg_wmt_tm) { | |
437 | p_linux_if = &pg_wmt_tm->linux_if; | |
438 | } else { | |
439 | wmt_tm_dprintk("[%s] fail! \n", __func__); | |
440 | return -EINVAL; | |
441 | } | |
442 | ||
443 | wmt_tm_dprintk("[%s] %d\n", __func__, p_linux_if->kernel_mode); | |
444 | ||
445 | *mode = (p_linux_if->kernel_mode) ? THERMAL_DEVICE_ENABLED : THERMAL_DEVICE_DISABLED; | |
446 | ||
447 | return 0; | |
448 | } | |
449 | ||
450 | static int wmt_thz_set_mode(struct thermal_zone_device *thz_dev, enum thermal_device_mode mode) | |
451 | { | |
452 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
453 | ||
454 | wmt_tm_dprintk("[%s]\n", __func__); | |
455 | ||
456 | ||
457 | if(pg_wmt_tm) { | |
458 | p_linux_if = &pg_wmt_tm->linux_if; | |
459 | } else { | |
460 | wmt_tm_dprintk("[%s] fail! \n", __func__); | |
461 | return -EINVAL; | |
462 | } | |
463 | ||
464 | wmt_tm_dprintk("[%s] %d\n", __func__, mode); | |
465 | ||
466 | p_linux_if->kernel_mode = mode; | |
467 | ||
468 | return 0; | |
469 | ||
470 | } | |
471 | ||
472 | static int wmt_thz_get_trip_type(struct thermal_zone_device *thz_dev, int trip, | |
473 | enum thermal_trip_type *type) | |
474 | { | |
475 | wmt_tm_dprintk("[mtktspa_get_trip_type] %d\n", trip); | |
476 | *type = g_thermal_trip[trip]; | |
477 | return 0; | |
478 | } | |
479 | ||
480 | static int wmt_thz_get_trip_temp(struct thermal_zone_device *thz_dev, int trip, unsigned long *pv) | |
481 | { | |
482 | wmt_tm_dprintk("[mtktspa_get_trip_temp] %d\n", trip); | |
483 | *pv = g_trip_temp[trip]; | |
484 | return 0; | |
485 | } | |
486 | ||
487 | static int wmt_thz_get_crit_temp(struct thermal_zone_device *thz_dev, unsigned long *pv) | |
488 | { | |
489 | wmt_tm_dprintk("[%s]\n", __func__); | |
490 | #define WMT_TM_TEMP_CRIT 85000 /* 85.000 degree Celsius */ | |
491 | *pv = WMT_TM_TEMP_CRIT; | |
492 | ||
493 | return 0; | |
494 | } | |
495 | ||
496 | /* +mtktspa_cooling_sysrst_ops+ */ | |
497 | static int wmt_cl_get_max_state(struct thermal_cooling_device *cool_dev, unsigned long *pv) | |
498 | { | |
499 | *pv = 1; | |
500 | /* wmt_tm_dprintk("[%s] %d\n", __func__, *pv); */ | |
501 | return 0; | |
502 | } | |
503 | ||
504 | static int wmt_cl_get_cur_state(struct thermal_cooling_device *cool_dev, unsigned long *pv) | |
505 | { | |
506 | *pv = cl_dev_state; | |
507 | /* wmt_tm_dprintk("[%s] %d\n", __func__, *pv); */ | |
508 | return 0; | |
509 | } | |
510 | ||
511 | static int wmt_cl_set_cur_state(struct thermal_cooling_device *cool_dev, unsigned long v) | |
512 | { | |
513 | /* wmt_tm_dprintk("[%s] %d\n", __func__, v); */ | |
514 | cl_dev_state = v; | |
515 | ||
516 | if (cl_dev_state == 1) { | |
517 | /* the temperature is over than the critical, system reboot. */ | |
518 | BUG(); | |
519 | } | |
520 | ||
521 | return 0; | |
522 | } | |
523 | ||
524 | /* -mtktspa_cooling_sysrst_ops- */ | |
525 | ||
526 | static int wmt_send_signal(int level) | |
527 | { | |
528 | int ret = 0; | |
529 | int thro = level; | |
530 | ||
531 | if (tm_input_pid == 0) { | |
532 | wmt_tm_dprintk("[%s] pid is empty\n", __func__); | |
533 | ret = -1; | |
534 | } | |
535 | ||
536 | wmt_tm_printk("[%s] pid is %d, %d, %d\n", __func__, tm_pid, tm_input_pid, thro); | |
537 | ||
538 | if (ret == 0 && tm_input_pid != tm_pid) { | |
539 | tm_pid = tm_input_pid; | |
540 | pg_task = get_pid_task(find_vpid(tm_pid), PIDTYPE_PID); | |
541 | } | |
542 | ||
543 | if (ret == 0 && pg_task) { | |
544 | siginfo_t info; | |
545 | info.si_signo = SIGIO; | |
546 | info.si_errno = 0; | |
547 | info.si_code = thro; | |
548 | info.si_addr = NULL; | |
549 | ret = send_sig_info(SIGIO, &info, pg_task); | |
550 | } | |
551 | ||
552 | if (ret != 0) | |
553 | wmt_tm_info("[%s] ret=%d\n", __func__, ret); | |
554 | ||
555 | return ret; | |
556 | } | |
557 | ||
558 | #define UNK_STAT -1 | |
559 | #define LOW_STAT 0 | |
560 | #define MID_STAT 1 | |
561 | #define HIGH_STAT 2 | |
562 | #define WFD_STAT 3 | |
563 | ||
564 | static inline unsigned long thro(unsigned long a, unsigned int b, unsigned int c) | |
565 | { | |
566 | ||
567 | unsigned long tmp; | |
568 | ||
569 | tmp = (a << 10) * b / c; | |
570 | ||
571 | return tmp >> 10; | |
572 | } | |
573 | ||
574 | static int wmt_judge_throttling(int index, int is_on, int interval) | |
575 | { | |
576 | /* | |
577 | * throttling_stat | |
578 | * 2 ( pa1=1,pa2=1 ) | |
579 | * UPPER ---- | |
580 | * 1 ( pa1=1,pa2=0 ) | |
581 | * LOWER ---- | |
582 | * 0 ( pa1=0,pa2=0 ) | |
583 | */ | |
584 | static unsigned int throttling_pre_stat = 0; | |
585 | static int mail_box[2] = {-1,-1}; | |
586 | ||
587 | static bool is_reset = false; | |
588 | ||
589 | unsigned long cur_thro = tx_throughput; | |
590 | static unsigned long thro_constraint = 99 * 1000; | |
591 | ||
592 | int cur_wifi_stat = 0; | |
593 | ||
594 | wmt_tm_dprintk("[%s]+ [0]=%d, [1]=%d || [%d] is %s\n", __func__, mail_box[0], mail_box[1], | |
595 | index, (is_on==1?"ON":"OFF")); | |
596 | mail_box[index] = is_on; | |
597 | ||
598 | if (mail_box[0] >= 0 && mail_box[1] >= 0) { | |
599 | cur_wifi_stat = mail_box[0] + mail_box[1]; | |
600 | ||
601 | /* | |
602 | * If Wifi-display is on, go to WFD_STAT state, and reset the throttling. | |
603 | */ | |
604 | if (tm_wfd_stat == 2) | |
605 | cur_wifi_stat = WFD_STAT; | |
606 | ||
607 | switch(cur_wifi_stat) { | |
608 | case WFD_STAT: | |
609 | if (throttling_pre_stat != WFD_STAT) { | |
610 | /* | |
611 | * Enter Wifi-Display status, reset all throttling. Dont affect the performance of Wifi-Display. | |
612 | */ | |
613 | wmt_send_signal(-1); | |
614 | below_low_time = 0; | |
615 | over_up_time = 0; | |
616 | throttling_pre_stat = WFD_STAT; | |
617 | wmt_tm_printk("WFD is on, reset everything!"); | |
618 | } | |
619 | break; | |
620 | ||
621 | case HIGH_STAT: | |
622 | if (throttling_pre_stat < HIGH_STAT || throttling_pre_stat == WFD_STAT) { | |
623 | if (cur_thro > 0) /*Wifi is working!!*/ | |
624 | thro_constraint = thro(cur_thro, up_numerator, up_denominator); | |
625 | else /*At this moment, current throughput is none. Use the previous constraint.*/ | |
626 | thro_constraint = thro(thro_constraint, up_numerator, up_denominator); | |
627 | ||
628 | wmt_tm_printk("LOW/MID-->HIGH:%lu <- (%d / %d) %lu", thro_constraint, up_numerator, up_denominator, cur_thro); | |
629 | ||
630 | wmt_send_signal( thro_constraint / 1000); | |
631 | throttling_pre_stat = HIGH_STAT; | |
632 | over_up_time = 0; | |
633 | } else if (throttling_pre_stat == HIGH_STAT) { | |
634 | over_up_time++; | |
635 | if ( (over_up_time * interval) >= up_duration) { | |
636 | if (cur_thro < thro_constraint) /*real throughput may have huge variant*/ | |
637 | thro_constraint = thro(cur_thro, up_numerator, up_denominator); | |
638 | else /* current throughput is large than constraint. WHAT!!!*/ | |
639 | thro_constraint = thro(thro_constraint, up_numerator, up_denominator); | |
640 | ||
641 | wmt_tm_printk("HIGH-->HIGH:%lu <- (%d / %d) %lu", thro_constraint, up_numerator, up_denominator, cur_thro); | |
642 | ||
643 | wmt_send_signal( thro_constraint / 1000); | |
644 | over_up_time = 0; | |
645 | } | |
646 | } else { | |
647 | wmt_tm_info("[%s] Error state1!! %u\n", __func__, | |
648 | throttling_pre_stat); | |
649 | } | |
650 | wmt_tm_printk("case2 time=%d\n", over_up_time); | |
651 | break; | |
652 | ||
653 | case MID_STAT: | |
654 | if (throttling_pre_stat == LOW_STAT) { | |
655 | below_low_time = 0; | |
656 | throttling_pre_stat = MID_STAT; | |
657 | wmt_tm_printk("[%s] Go up!!\n", __func__); | |
658 | } else if (throttling_pre_stat == HIGH_STAT) { | |
659 | over_up_time = 0; | |
660 | throttling_pre_stat = MID_STAT; | |
661 | wmt_tm_printk("[%s] Go down!!\n", __func__); | |
662 | } else { | |
663 | throttling_pre_stat = MID_STAT; | |
664 | wmt_tm_dprintk("[%s] pre_stat=%d!!\n", __func__, throttling_pre_stat); | |
665 | } | |
666 | break; | |
667 | ||
668 | case LOW_STAT: | |
669 | if (throttling_pre_stat == WFD_STAT) { | |
670 | throttling_pre_stat = LOW_STAT; | |
671 | wmt_tm_dprintk("[%s] pre_stat=%d!!\n", __func__, throttling_pre_stat); | |
672 | } else if (throttling_pre_stat > LOW_STAT) { | |
673 | if (cur_thro < 5000 && cur_thro > 0) { | |
674 | thro_constraint = cur_thro * 3; | |
675 | } else if (cur_thro >= 5000) { | |
676 | thro_constraint = thro(cur_thro, low_numerator, low_denominator); | |
677 | } else { | |
678 | thro_constraint = thro(thro_constraint, low_numerator, low_denominator); | |
679 | } | |
680 | ||
681 | wmt_tm_printk("MID/HIGH-->LOW:%lu <- (%d / %d) %lu", thro_constraint, low_numerator, low_denominator, cur_thro); | |
682 | wmt_send_signal( thro_constraint / 1000); | |
683 | throttling_pre_stat = LOW_STAT; | |
684 | below_low_time = 0; | |
685 | low_rst_time = 0; | |
686 | is_reset = false; | |
687 | } else if (throttling_pre_stat == LOW_STAT) { | |
688 | below_low_time++; | |
689 | if ( (below_low_time*interval) >= low_duration) { | |
690 | if (low_rst_time >= low_rst_max && !is_reset) { | |
691 | wmt_tm_printk("over rst time=%d", low_rst_time); | |
692 | ||
693 | wmt_send_signal(-1); //reset | |
694 | low_rst_time = low_rst_max; | |
695 | is_reset = true; | |
696 | } else if(!is_reset) { | |
697 | if (cur_thro < 5000 && cur_thro > 0) { | |
698 | thro_constraint = cur_thro * 3; | |
699 | } else if (cur_thro >= 5000) { | |
700 | thro_constraint = thro(cur_thro, low_numerator, low_denominator); | |
701 | low_rst_time++; | |
702 | } else { | |
703 | thro_constraint = thro(thro_constraint, low_numerator, low_denominator); | |
704 | low_rst_time++; | |
705 | } | |
706 | ||
707 | wmt_tm_printk("LOW-->LOW:%lu <-(%d / %d) %lu", thro_constraint, low_numerator, low_denominator, cur_thro); | |
708 | ||
709 | wmt_send_signal( thro_constraint / 1000); | |
710 | below_low_time = 0; | |
711 | } else { | |
712 | wmt_tm_dprintk("Have reset, no control!!"); | |
713 | } | |
714 | } | |
715 | } else { | |
716 | wmt_tm_info("[%s] Error state3 %d!!\n", __func__, throttling_pre_stat); | |
717 | } | |
718 | wmt_tm_dprintk("case0 time=%d, rst=%d %d\n", below_low_time, low_rst_time, is_reset); | |
719 | break; | |
720 | ||
721 | default: | |
722 | wmt_tm_info("[%s] Error cur_wifi_stat=%d!!\n", __func__, cur_wifi_stat); | |
723 | break; | |
724 | } | |
725 | ||
726 | mail_box[0] = UNK_STAT; | |
727 | mail_box[1] = UNK_STAT; | |
728 | } else { | |
729 | wmt_tm_dprintk("[%s] dont get all info!!\n", __func__); | |
730 | } | |
731 | return 0; | |
732 | } | |
733 | ||
734 | /* +mtktspa_cooling_pa1_ops+ */ | |
735 | static int wmt_cl_pa1_get_max_state(struct thermal_cooling_device *cool_dev, unsigned long *pv) | |
736 | { | |
737 | *pv = 1; | |
738 | /* wmt_tm_dprintk("[%s] %d\n", __func__, *pv); */ | |
739 | return 0; | |
740 | } | |
741 | ||
742 | static int wmt_cl_pa1_get_cur_state(struct thermal_cooling_device *cool_dev, unsigned long *pv) | |
743 | { | |
744 | *pv = cl_pa1_dev_state; | |
745 | /* wmt_tm_dprintk("[%s] %d\n", __func__, *pv); */ | |
746 | return 0; | |
747 | } | |
748 | ||
749 | static int wmt_cl_pa1_set_cur_state(struct thermal_cooling_device *cool_dev, unsigned long v) | |
750 | { | |
751 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
752 | int ret = 0; | |
753 | ||
754 | /* wmt_tm_dprintk("[%s] %d\n", __func__, v); */ | |
755 | ||
756 | if (pg_wmt_tm) { | |
757 | p_linux_if = &pg_wmt_tm->linux_if; | |
758 | } else { | |
759 | ret = -1; | |
760 | } | |
761 | ||
762 | cl_pa1_dev_state = (unsigned int)v; | |
763 | ||
764 | if (cl_pa1_dev_state == 1) { | |
765 | ret = wmt_judge_throttling(0, 1, p_linux_if->interval/1000); | |
766 | } else { | |
767 | ret = wmt_judge_throttling(0, 0, p_linux_if->interval/1000); | |
768 | } | |
769 | if (ret != 0) | |
770 | wmt_tm_info("[%s] ret=%d\n", __func__, ret); | |
771 | return ret; | |
772 | } | |
773 | ||
774 | /* -mtktspa_cooling_pa1_ops- */ | |
775 | ||
776 | /* +mtktspa_cooling_pa2_ops+ */ | |
777 | static int wmt_cl_pa2_get_max_state(struct thermal_cooling_device *cool_dev, unsigned long *pv) | |
778 | { | |
779 | *pv = 1; | |
780 | /* wmt_tm_dprintk("[%s] %d\n", __func__, *pv); */ | |
781 | return 0; | |
782 | } | |
783 | ||
784 | static int wmt_cl_pa2_get_cur_state(struct thermal_cooling_device *cool_dev, unsigned long *pv) | |
785 | { | |
786 | *pv = cl_pa2_dev_state; | |
787 | /* wmt_tm_dprintk("[%s] %d\n", __func__, *pv); */ | |
788 | return 0; | |
789 | } | |
790 | ||
791 | static int wmt_cl_pa2_set_cur_state(struct thermal_cooling_device *cool_dev, unsigned long v) | |
792 | { | |
793 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
794 | int ret = 0; | |
795 | ||
796 | /* wmt_tm_dprintk("[%s] %d\n", __func__, v); */ | |
797 | ||
798 | if (pg_wmt_tm) { | |
799 | p_linux_if = &pg_wmt_tm->linux_if; | |
800 | } else { | |
801 | ret = -1; | |
802 | } | |
803 | ||
804 | cl_pa2_dev_state = (unsigned int)v; | |
805 | ||
806 | if (cl_pa2_dev_state == 1) { | |
807 | ret = wmt_judge_throttling(1, 1, p_linux_if->interval/1000); | |
808 | } else { | |
809 | ret = wmt_judge_throttling(1, 0, p_linux_if->interval/1000); | |
810 | } | |
811 | if (ret != 0) | |
812 | wmt_tm_info("[%s] ret=%d\n", __func__, ret); | |
813 | return ret; | |
814 | } | |
815 | ||
816 | /* -mtktspa_cooling_pa2_ops- */ | |
817 | ||
818 | #ifdef NEVER | |
819 | /* +mtktspa_cooling_pa3_ops+ */ | |
820 | static int wmt_cl_pa3_get_max_state(struct thermal_cooling_device *cool_dev, unsigned long *pv) | |
821 | { | |
822 | *pv = 1; | |
823 | wmt_tm_dprintk("[%s] %d\n", __func__, *pv); | |
824 | return 0; | |
825 | } | |
826 | ||
827 | static int wmt_cl_pa3_get_cur_state(struct thermal_cooling_device *cool_dev, unsigned long *pv) | |
828 | { | |
829 | *pv = cl_pa3_dev_state; | |
830 | wmt_tm_dprintk("[%s] %d\n", __func__, *pv); | |
831 | return 0; | |
832 | } | |
833 | ||
834 | static int wmt_cl_pa3_set_cur_state(struct thermal_cooling_device *cool_dev, unsigned long v) | |
835 | { | |
836 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
837 | int ret = 0; | |
838 | ||
839 | wmt_tm_dprintk("[%s] %d\n", __func__, v); | |
840 | ||
841 | if (pg_wmt_tm) { | |
842 | p_linux_if = &pg_wmt_tm->linux_if; | |
843 | } else { | |
844 | ret = -1; | |
845 | } | |
846 | ||
847 | cl_pa3_dev_state = (unsigned int)v; | |
848 | ||
849 | if (cl_pa3_dev_state == 1) { | |
850 | /* ret = wmt_arbitrate_thro(2,3); */ | |
851 | } else { | |
852 | /* ret = wmt_arbitrate_thro(2,0); */ | |
853 | } | |
854 | if (ret != 0) | |
855 | wmt_tm_printk("[%s] ret=%d\n", __func__, ret); | |
856 | return ret; | |
857 | } | |
858 | ||
859 | /* -mtktspa_cooling_pa3_ops- */ | |
860 | #endif /* NEVER */ | |
861 | ||
862 | int wmt_wifi_tx_thro_read(struct seq_file *m, void *v) | |
863 | { | |
864 | seq_printf(m, "%lu\n", tx_throughput); | |
865 | ||
866 | wmt_tm_dprintk("[%s] tx=%lu\n", __func__, tx_throughput); | |
867 | ||
868 | return 0; | |
869 | } | |
870 | ||
871 | static int wmt_wifi_tx_thro_open(struct inode *inode, struct file *file) | |
872 | { | |
873 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
874 | return single_open(file, wmt_wifi_tx_thro_read, PDE_DATA(inode)); | |
875 | #else | |
876 | return single_open(file, wmt_wifi_tx_thro_read, PDE(inode)->data); | |
877 | #endif | |
878 | } | |
879 | ||
880 | /*New Wifi throttling Algo+*/ | |
881 | ssize_t wmt_wifi_algo_write(struct file *filp, const char __user *buf, size_t len, loff_t *data) | |
882 | { | |
883 | char desc[MAX_LEN] = {0}; | |
884 | ||
885 | unsigned int tmp_up_dur = 30; | |
886 | unsigned int tmp_up_den = 2; | |
887 | unsigned int tmp_up_num = 1; | |
888 | ||
889 | unsigned int tmp_low_dur = 3; | |
890 | unsigned int tmp_low_den = 2; | |
891 | unsigned int tmp_low_num = 3; | |
892 | ||
893 | unsigned int tmp_low_rst_max = 3; | |
894 | ||
895 | unsigned int tmp_log = 0; | |
896 | ||
897 | len = (len < (sizeof(desc) - 1)) ? len : (sizeof(desc) - 1); | |
898 | ||
899 | /* write data to the buffer */ | |
900 | if (copy_from_user(desc, buf, len)) { | |
901 | return -EFAULT; | |
902 | } | |
903 | ||
904 | if (sscanf(desc, "%d %d/%d %d %d/%d %d", &tmp_up_dur, &tmp_up_num, &tmp_up_den, &tmp_low_dur, \ | |
905 | &tmp_low_num, &tmp_low_den, &tmp_low_rst_max) == 7) { | |
906 | ||
907 | up_duration = tmp_up_dur; | |
908 | up_denominator = tmp_up_den; | |
909 | up_numerator = tmp_up_num; | |
910 | ||
911 | low_duration = tmp_low_dur; | |
912 | low_denominator = tmp_low_den; | |
913 | low_numerator = tmp_low_num; | |
914 | ||
915 | low_rst_max = tmp_low_rst_max; | |
916 | ||
917 | over_up_time = 0; | |
918 | below_low_time = 0; | |
919 | low_rst_time = 0; | |
920 | ||
921 | wmt_tm_printk("[%s] %s [up]%d %d/%d, [low]%d %d/%d, rst=%d\n", __func__, desc, up_duration, \ | |
922 | up_numerator, up_denominator, low_duration, low_numerator, low_denominator, low_rst_max); | |
923 | ||
924 | return len; | |
925 | } else if (sscanf(desc, "log=%d", &tmp_log) == 1) { | |
926 | if (tmp_log == 1) | |
927 | wmt_tm_debug_log = 1; | |
928 | else | |
929 | wmt_tm_debug_log = 0; | |
930 | ||
931 | return len; | |
932 | } else { | |
933 | wmt_tm_printk("[%s] bad argument = %s\n", __func__, desc); | |
934 | } | |
935 | return -EINVAL; | |
936 | } | |
937 | ||
938 | int wmt_wifi_algo_read(struct seq_file *m, void *v) | |
939 | { | |
940 | /* int ret; */ | |
941 | /* char tmp[MAX_LEN] = {0}; */ | |
942 | ||
943 | seq_printf(m, "[up]\t%3d(sec)\t%2d/%2d\n[low]\t%3d(sec)\t%2d/%2d\nrst=%2d\n", up_duration, | |
944 | up_numerator, up_denominator, low_duration, low_numerator, low_denominator, | |
945 | low_rst_max); | |
946 | /* ret = strlen(tmp); */ | |
947 | ||
948 | /* memcpy(buf, tmp, ret*sizeof(char)); */ | |
949 | ||
950 | wmt_tm_printk("[%s] [up]%d %d/%d, [low]%d %d/%d, rst=%d\n", __func__, up_duration, \ | |
951 | up_numerator, up_denominator, low_duration, low_numerator, low_denominator, low_rst_max); | |
952 | ||
953 | return 0; | |
954 | } | |
955 | ||
956 | static int wmt_wifi_algo_open(struct inode *inode, struct file *file) | |
957 | { | |
958 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
959 | return single_open(file, wmt_wifi_algo_read, PDE_DATA(inode)); | |
960 | #else | |
961 | return single_open(file, wmt_wifi_algo_read, PDE(inode)->data); | |
962 | #endif | |
963 | } | |
964 | ||
965 | /*New Wifi throttling Algo-*/ | |
966 | ||
967 | ssize_t wmt_tm_wfd_write(struct file *filp, const char __user *buf, size_t len, loff_t *data) | |
968 | { | |
969 | int ret = 0; | |
970 | char tmp[MAX_LEN] = {0}; | |
971 | ||
4b9e9796 | 972 | len = (len < (MAX_LEN-1)) ? len : (MAX_LEN-1); |
6fa3eb70 S |
973 | /* write data to the buffer */ |
974 | if (copy_from_user(tmp, buf, len)) { | |
975 | return -EFAULT; | |
976 | } | |
977 | ||
978 | ret = sscanf(tmp, "%d", &tm_wfd_stat); | |
979 | ||
980 | wmt_tm_printk("[%s] %s = %d, len=%d, ret=%d\n", __func__, tmp, tm_wfd_stat, len, ret); | |
981 | ||
982 | return len; | |
983 | } | |
984 | ||
985 | int wmt_tm_wfd_read(struct seq_file *m, void *v) | |
986 | { | |
987 | /* int len; */ | |
988 | /* int ret = 0; */ | |
989 | /* char tmp[MAX_LEN] = {0}; */ | |
990 | ||
991 | seq_printf(m, "%d\n", tm_wfd_stat); | |
992 | /* len = strlen(tmp); */ | |
993 | ||
994 | /* memcpy(buf, tmp, ret*sizeof(char)); */ | |
995 | ||
996 | wmt_tm_printk("[%s] %d\n", __func__, tm_wfd_stat); | |
997 | ||
998 | return 0; | |
999 | } | |
1000 | ||
1001 | static int wmt_tm_wfd_open(struct inode *inode, struct file *file) | |
1002 | { | |
1003 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
1004 | return single_open(file, wmt_tm_wfd_read, PDE_DATA(inode)); | |
1005 | #else | |
1006 | return single_open(file, wmt_tm_wfd_read, PDE(inode)->data); | |
1007 | #endif | |
1008 | } | |
1009 | ||
1010 | ssize_t wmt_tm_pid_write(struct file *filp, const char __user *buf, size_t len, loff_t *data) | |
1011 | { | |
1012 | int ret = 0; | |
1013 | char tmp[MAX_LEN] = {0}; | |
1014 | ||
4b9e9796 | 1015 | len = (len < (MAX_LEN-1)) ? len : (MAX_LEN-1); |
6fa3eb70 S |
1016 | /* write data to the buffer */ |
1017 | if ( copy_from_user(tmp, buf, len) ) { | |
1018 | return -EFAULT; | |
1019 | } | |
1020 | ||
1021 | ret = kstrtouint(tmp, 10, &tm_input_pid); | |
1022 | if (ret) | |
1023 | WARN_ON(1); | |
1024 | ||
1025 | wmt_tm_printk("[%s] %s = %d\n", __func__, tmp, tm_input_pid); | |
1026 | ||
1027 | return len; | |
1028 | } | |
1029 | ||
1030 | int wmt_tm_pid_read(struct seq_file *m, void *v) | |
1031 | { | |
1032 | /* int ret; */ | |
1033 | /* char tmp[MAX_LEN] = {0}; */ | |
1034 | ||
1035 | seq_printf(m, "%d\n", tm_input_pid); | |
1036 | /* ret = strlen(tmp); */ | |
1037 | ||
1038 | /* memcpy(buf, tmp, ret*sizeof(char)); */ | |
1039 | ||
1040 | wmt_tm_printk("[%s] %d\n", __func__, tm_input_pid); | |
1041 | ||
1042 | return 0; | |
1043 | } | |
1044 | ||
1045 | static int wmt_tm_pid_open(struct inode *inode, struct file *file) | |
1046 | { | |
1047 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
1048 | return single_open(file, wmt_tm_pid_read, PDE_DATA(inode)); | |
1049 | #else | |
1050 | return single_open(file, wmt_tm_pid_read, PDE(inode)->data); | |
1051 | #endif | |
1052 | } | |
1053 | ||
1054 | #define check_str(x) (x[0]=='\0'?"none\t":x) | |
1055 | ||
1056 | static int wmt_tm_read(struct seq_file *m, void *v) | |
1057 | { | |
1058 | /* int len = 0; */ | |
1059 | /* char *p = buf; */ | |
1060 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
1061 | ||
1062 | wmt_tm_printk("[%s]\n", __func__); | |
1063 | ||
1064 | /* sanity */ | |
1065 | if(pg_wmt_tm) { | |
1066 | p_linux_if = &pg_wmt_tm->linux_if; | |
1067 | } else { | |
1068 | wmt_tm_info("[wmt_tm_read] fail! \n"); | |
1069 | return -EINVAL; | |
1070 | } | |
1071 | ||
1072 | seq_printf(m, "[wmt_tm_read]" | |
1073 | "\n \tcooler\t\ttrip_temp\ttrip_type" | |
1074 | "\n [0] %s\t%d\t\t%d" | |
1075 | "\n [1] %s\t%d\t\t%d" | |
1076 | "\n [2] %s\t%d\t\t%d" | |
1077 | "\n [3] %s\t%d\t\t%d" | |
1078 | "\n [4] %s\t%d\t\t%d" | |
1079 | "\n [5] %s\t%d\t\t%d" | |
1080 | "\n [6] %s\t%d\t\t%d" | |
1081 | "\n [7] %s\t%d\t\t%d" | |
1082 | "\n [8] %s\t%d\t\t%d" | |
1083 | "\n [9] %s\t%d\t\t%d" | |
1084 | "\ntime_ms=%d\n", | |
1085 | check_str(g_bind0), g_trip_temp[0], g_thermal_trip[0], check_str(g_bind1), | |
1086 | g_trip_temp[1], g_thermal_trip[1], check_str(g_bind2), g_trip_temp[2], | |
1087 | g_thermal_trip[2], check_str(g_bind3), g_trip_temp[3], g_thermal_trip[3], | |
1088 | check_str(g_bind4), g_trip_temp[4], g_thermal_trip[4], check_str(g_bind5), | |
1089 | g_trip_temp[5], g_thermal_trip[5], check_str(g_bind6), g_trip_temp[6], | |
1090 | g_thermal_trip[6], check_str(g_bind7), g_trip_temp[7], g_thermal_trip[7], | |
1091 | check_str(g_bind8), g_trip_temp[8], g_thermal_trip[8], check_str(g_bind9), | |
1092 | g_trip_temp[9], g_thermal_trip[9], p_linux_if->interval); | |
1093 | ||
1094 | return 0; | |
1095 | } | |
1096 | ||
1097 | static int wmt_tm_open(struct inode *inode, struct file *file) | |
1098 | { | |
1099 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
1100 | return single_open(file, wmt_tm_read, PDE_DATA(inode)); | |
1101 | #else | |
1102 | return single_open(file, wmt_tm_read, PDE(inode)->data); | |
1103 | #endif | |
1104 | } | |
1105 | ||
1106 | static ssize_t wmt_tm_write(struct file *filp, const char __user *buf, size_t count, loff_t *data) | |
1107 | { | |
1108 | int i = 0; | |
1109 | int len=0,time_msec=0; | |
1110 | int trip_temp[COOLER_NUM] = {0}; | |
1111 | int thermal_trip[COOLER_NUM] = {0}; | |
1112 | ||
1113 | char desc[512]; | |
1114 | char bind0[20],bind1[20],bind2[20],bind3[20],bind4[20]; | |
1115 | char bind5[20],bind6[20],bind7[20],bind8[20],bind9[20]; | |
1116 | ||
1117 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
1118 | ||
1119 | wmt_tm_printk("[%s]\n", __func__); | |
1120 | ||
1121 | /* sanity */ | |
1122 | if(pg_wmt_tm) { | |
1123 | p_linux_if = &pg_wmt_tm->linux_if; | |
1124 | } else { | |
1125 | wmt_tm_info("[wmt_thz_write] fail! \n"); | |
1126 | return -EINVAL; | |
1127 | } | |
1128 | ||
1129 | len = (count < (sizeof(desc) - 1)) ? count : (sizeof(desc) - 1); | |
1130 | ||
1131 | if (copy_from_user(desc, buf, len)) { | |
1132 | return 0; | |
1133 | } | |
1134 | ||
1135 | desc[len] = '\0'; | |
1136 | ||
1137 | if (sscanf | |
1138 | (desc, | |
1139 | "%d %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d %d %s %d", | |
1140 | &g_num_trip, &trip_temp[0], &thermal_trip[0], bind0, &trip_temp[1], &thermal_trip[1], | |
1141 | bind1, &trip_temp[2], &thermal_trip[2], bind2, &trip_temp[3], &thermal_trip[3], bind3, | |
1142 | &trip_temp[4], &thermal_trip[4], bind4, &trip_temp[5], &thermal_trip[5], bind5, | |
1143 | &trip_temp[6], &thermal_trip[6], bind6, &trip_temp[7], &thermal_trip[7], bind7, | |
1144 | &trip_temp[8], &thermal_trip[8], bind8, &trip_temp[9], &thermal_trip[9], bind9, | |
1145 | &time_msec) == 32) { | |
1146 | /* unregister */ | |
1147 | if (p_linux_if->thz_dev) { | |
1148 | mtk_thermal_zone_device_unregister(p_linux_if->thz_dev); | |
1149 | p_linux_if->thz_dev = NULL; | |
1150 | } | |
1151 | ||
1152 | for ( i = 0; i < g_num_trip; i++) { | |
1153 | g_thermal_trip[i] = thermal_trip[i]; | |
1154 | } | |
1155 | ||
1156 | g_bind0[0]=g_bind1[0]=g_bind2[0]=g_bind3[0]=g_bind4[0]='\0'; | |
1157 | g_bind5[0]=g_bind6[0]=g_bind7[0]=g_bind8[0]=g_bind9[0]='\0'; | |
1158 | ||
1159 | for ( i = 0; i < 20; i++ ) { | |
1160 | g_bind0[i]=bind0[i]; | |
1161 | g_bind1[i]=bind1[i]; | |
1162 | g_bind2[i]=bind2[i]; | |
1163 | g_bind3[i]=bind3[i]; | |
1164 | g_bind4[i]=bind4[i]; | |
1165 | g_bind5[i]=bind5[i]; | |
1166 | g_bind6[i]=bind6[i]; | |
1167 | g_bind7[i]=bind7[i]; | |
1168 | g_bind8[i]=bind8[i]; | |
1169 | g_bind9[i]=bind9[i]; | |
1170 | } | |
1171 | ||
1172 | for ( i = 0; i < g_num_trip; i++) { | |
1173 | g_trip_temp[i] = trip_temp[i]; | |
1174 | } | |
1175 | ||
1176 | p_linux_if->interval = time_msec; | |
1177 | ||
1178 | wmt_tm_dprintk("[wmt_tm_write] g_trip_temp [0]=%d, [1]=%d, [2]=%d, [3]=%d, [4]=%d\n", | |
1179 | g_thermal_trip[0], g_thermal_trip[1], g_thermal_trip[2], | |
1180 | g_thermal_trip[3], g_thermal_trip[4]); | |
1181 | ||
1182 | wmt_tm_dprintk("[wmt_tm_write] g_trip_temp [5]=%d, [6]=%d, [7]=%d, [8]=%d, [9]=%d\n", | |
1183 | g_thermal_trip[5], g_thermal_trip[6], g_thermal_trip[7], | |
1184 | g_thermal_trip[8], g_thermal_trip[9]); | |
1185 | ||
1186 | wmt_tm_dprintk("[wmt_tm_write] cooldev [0]=%s, [1]=%s, [2]=%s, [3]=%s, [4]=%s,\n", | |
1187 | g_bind0, g_bind1, g_bind2, g_bind3, g_bind4); | |
1188 | ||
1189 | wmt_tm_dprintk("[wmt_tm_write] cooldev [5]=%s, [6]=%s, [7]=%s, [8]=%s, [9]=%s,\n", | |
1190 | g_bind5, g_bind6, g_bind7, g_bind8, g_bind9); | |
1191 | ||
1192 | wmt_tm_dprintk("[wmt_tm_write] trip_temp [0]=%d, [1]=%d, [2]=%d, [3]=%d, [4]=%d\n", | |
1193 | trip_temp[0], trip_temp[1], trip_temp[2], trip_temp[3], trip_temp[4]); | |
1194 | ||
1195 | wmt_tm_dprintk("[wmt_tm_write] trip_temp [5]=%d, [6]=%d, [7]=%d, [8]=%d, [9]=%d\n", | |
1196 | trip_temp[5], trip_temp[6], trip_temp[7], trip_temp[8], trip_temp[9]); | |
1197 | ||
1198 | wmt_tm_dprintk("[wmt_tm_write] polling time=%d\n", p_linux_if->interval); | |
1199 | ||
1200 | /* p_linux_if->thz_dev->polling_delay = p_linux_if->interval*1000; */ | |
1201 | ||
1202 | /* thermal_zone_device_update(p_linux_if->thz_dev); */ | |
1203 | ||
1204 | /* register */ | |
1205 | p_linux_if->thz_dev = mtk_thermal_zone_device_register("mtktswmt", g_num_trip, NULL, | |
1206 | &wmt_thz_dev_ops, 0, 0, 0, p_linux_if->interval); | |
1207 | ||
1208 | wmt_tm_dprintk("[wmt_tm_write] time_ms=%d\n", p_linux_if->interval); | |
1209 | ||
1210 | return count; | |
1211 | } else { | |
1212 | wmt_tm_info("[%s] bad argument = %s\n", __func__, desc); | |
1213 | } | |
1214 | ||
1215 | return -EINVAL; | |
1216 | } | |
1217 | ||
1218 | static const struct file_operations _wmt_tm_fops = { | |
1219 | .owner = THIS_MODULE, | |
1220 | .open = wmt_tm_open, | |
1221 | .read = seq_read, | |
1222 | .llseek = seq_lseek, | |
1223 | .write = wmt_tm_write, | |
1224 | .release = single_release, | |
1225 | }; | |
1226 | ||
1227 | static const struct file_operations _tm_pid_fops = { | |
1228 | .owner = THIS_MODULE, | |
1229 | .open = wmt_tm_pid_open, | |
1230 | .read = seq_read, | |
1231 | .llseek = seq_lseek, | |
1232 | .write = wmt_tm_pid_write, | |
1233 | .release = single_release, | |
1234 | }; | |
1235 | ||
1236 | static const struct file_operations _wmt_val_fops = { | |
1237 | .owner = THIS_MODULE, | |
1238 | .open = wmt_wifi_algo_open, | |
1239 | .read = seq_read, | |
1240 | .llseek = seq_lseek, | |
1241 | .write = wmt_wifi_algo_write, | |
1242 | .release = single_release, | |
1243 | }; | |
1244 | ||
1245 | static const struct file_operations _tx_thro_fops = { | |
1246 | .owner = THIS_MODULE, | |
1247 | .open = wmt_wifi_tx_thro_open, | |
1248 | .read = seq_read, | |
1249 | .llseek = seq_lseek, | |
1250 | .release = single_release, | |
1251 | }; | |
1252 | ||
1253 | static const struct file_operations _wfd_stat_fops = { | |
1254 | .owner = THIS_MODULE, | |
1255 | .open = wmt_tm_wfd_open, | |
1256 | .read = seq_read, | |
1257 | .llseek = seq_lseek, | |
1258 | .write = wmt_tm_wfd_write, | |
1259 | .release = single_release, | |
1260 | }; | |
1261 | ||
1262 | static int wmt_tm_proc_register(void) | |
1263 | { | |
1264 | struct proc_dir_entry *entry = NULL; | |
1265 | struct proc_dir_entry *wmt_tm_proc_dir = NULL; | |
1266 | ||
1267 | wmt_tm_dprintk("[%s]\n", __func__); | |
1268 | ||
1269 | wmt_tm_proc_dir = mtk_thermal_get_proc_drv_therm_dir_entry(); | |
1270 | if (!wmt_tm_proc_dir) { | |
1271 | wmt_tm_printk("[%s]: mkdir /proc/driver/thermal failed\n", __func__); | |
1272 | } else { | |
1273 | entry = | |
1274 | proc_create("tzwmt", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, wmt_tm_proc_dir, | |
1275 | &_wmt_tm_fops); | |
1276 | if (entry) { | |
1277 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
1278 | proc_set_user(entry, 0, 1000); | |
1279 | #else | |
1280 | entry->gid = 1000; | |
1281 | #endif | |
1282 | } | |
1283 | ||
1284 | entry = | |
1285 | proc_create("clwmt_pid", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, wmt_tm_proc_dir, | |
1286 | &_tm_pid_fops); | |
1287 | if (entry) { | |
1288 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
1289 | proc_set_user(entry, 0, 1000); | |
1290 | #else | |
1291 | entry->gid = 1000; | |
1292 | #endif | |
1293 | } | |
1294 | ||
1295 | entry = | |
1296 | proc_create("clwmt_val", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, wmt_tm_proc_dir, | |
1297 | &_wmt_val_fops); | |
1298 | if (entry) { | |
1299 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
1300 | proc_set_user(entry, 0, 1000); | |
1301 | #else | |
1302 | entry->gid = 1000; | |
1303 | #endif | |
1304 | } | |
1305 | ||
1306 | entry = proc_create("wifi_tx_thro", S_IRUGO | S_IWUSR, wmt_tm_proc_dir, &_tx_thro_fops); | |
1307 | ||
1308 | entry = | |
1309 | proc_create("clwmt_wfdstat", S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, wmt_tm_proc_dir, | |
1310 | &_wfd_stat_fops); | |
1311 | if (entry) { | |
1312 | #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 10, 0) | |
1313 | proc_set_user(entry, 0, 1000); | |
1314 | #else | |
1315 | entry->gid = 1000; | |
1316 | #endif | |
1317 | } | |
1318 | } | |
1319 | return 0; | |
1320 | } | |
1321 | ||
1322 | static int wmt_tm_proc_unregister(void) | |
1323 | { | |
1324 | wmt_tm_dprintk("[%s]\n", __func__); | |
1325 | /* remove_proc_entry("wmt_tm", proc_entry); */ | |
1326 | return 0; | |
1327 | } | |
1328 | ||
1329 | static int wmt_tm_thz_cl_register(void) | |
1330 | { | |
1331 | #define DEFAULT_POLL_TIME 0 /*Default disable, turn on by thermal policy*/ | |
1332 | ||
1333 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
1334 | ||
1335 | wmt_tm_dprintk("[%s]\n", __func__); | |
1336 | ||
1337 | if(pg_wmt_tm) { | |
1338 | p_linux_if = &pg_wmt_tm->linux_if; | |
1339 | } else { | |
1340 | return -1; | |
1341 | } | |
1342 | ||
1343 | /* cooling devices */ | |
1344 | p_linux_if->cl_dev = mtk_thermal_cooling_device_register("mtktswmt-sysrst", NULL, | |
1345 | &mtktspa_cooling_sysrst_ops); | |
1346 | ||
1347 | p_linux_if->cl_pa1_dev = mtk_thermal_cooling_device_register("mtktswmt-pa1", NULL, | |
1348 | &mtktspa_cooling_pa1_ops); | |
1349 | ||
1350 | p_linux_if->cl_pa2_dev = mtk_thermal_cooling_device_register("mtktswmt-pa2", NULL, | |
1351 | &mtktspa_cooling_pa2_ops); | |
1352 | ||
1353 | #ifdef NEVER | |
1354 | p_linux_if->cl_pa3_dev = mtk_thermal_cooling_device_register("mtktswmt-pa3", NULL, | |
1355 | &mtktspa_cooling_pa3_ops); | |
1356 | #endif /* NEVER */ | |
1357 | ||
1358 | p_linux_if->interval = DEFAULT_POLL_TIME; | |
1359 | ||
1360 | /* trips */ | |
1361 | p_linux_if->thz_dev = mtk_thermal_zone_device_register("mtktswmt", g_num_trip, NULL, | |
1362 | &wmt_thz_dev_ops, 0, 0, 0, p_linux_if->interval); | |
1363 | ||
1364 | return 0; | |
1365 | } | |
1366 | ||
1367 | static int wmt_tm_thz_cl_unregister(void) | |
1368 | { | |
1369 | struct linux_thermal_ctrl_if *p_linux_if = 0; | |
1370 | ||
1371 | wmt_tm_dprintk("[%s]\n", __func__); | |
1372 | ||
1373 | if(pg_wmt_tm) { | |
1374 | p_linux_if = &pg_wmt_tm->linux_if; | |
1375 | } else { | |
1376 | return -1; | |
1377 | } | |
1378 | ||
1379 | if (p_linux_if->cl_dev) { | |
1380 | mtk_thermal_cooling_device_unregister(p_linux_if->cl_dev); | |
1381 | p_linux_if->cl_dev = NULL; | |
1382 | } | |
1383 | ||
1384 | if (p_linux_if->cl_pa1_dev) { | |
1385 | mtk_thermal_cooling_device_unregister(p_linux_if->cl_pa1_dev); | |
1386 | p_linux_if->cl_pa1_dev = NULL; | |
1387 | } | |
1388 | ||
1389 | if (p_linux_if->cl_pa2_dev) { | |
1390 | mtk_thermal_cooling_device_unregister(p_linux_if->cl_pa2_dev); | |
1391 | p_linux_if->cl_pa2_dev = NULL; | |
1392 | } | |
1393 | ||
1394 | #ifdef NEVER | |
1395 | if (p_linux_if->cl_pa3_dev) { | |
1396 | mtk_thermal_cooling_device_unregister(p_linux_if->cl_pa3_dev); | |
1397 | p_linux_if->cl_pa3_dev = NULL; | |
1398 | } | |
1399 | #endif /* NEVER */ | |
1400 | ||
1401 | if (p_linux_if->thz_dev) { | |
1402 | mtk_thermal_zone_device_unregister(p_linux_if->thz_dev); | |
1403 | p_linux_if->thz_dev = NULL; | |
1404 | } | |
1405 | ||
1406 | return 0; | |
1407 | } | |
1408 | ||
1409 | #if 0 | |
1410 | static int wmt_tm_ops_register(struct wmt_thermal_ctrl_ops *ops) | |
1411 | { | |
1412 | struct wmt_thermal_ctrl_ops *p_des; | |
1413 | ||
1414 | wmt_tm_printk("[%s]\n", __func__); | |
1415 | ||
1416 | if (pg_wmt_tm) { | |
1417 | #if 1 | |
1418 | p_des = &pg_wmt_tm->wmt_if.ops; | |
1419 | if (ops!=NULL) { | |
1420 | wmt_tm_printk("[wmt_tm_ops_register] reg start ...\n"); | |
1421 | p_des->query_temp = ops->query_temp; | |
1422 | p_des->set_temp = ops->set_temp; | |
1423 | wmt_tm_printk("[wmt_tm_ops_register] reg end ...\n"); | |
1424 | } else { | |
1425 | p_des->query_temp = 0; | |
1426 | p_des->set_temp = 0; | |
1427 | } | |
1428 | #endif | |
1429 | return 0; | |
1430 | } else { | |
1431 | return -1; | |
1432 | } | |
1433 | } | |
1434 | ||
1435 | static int wmt_tm_ops_unregister(void) | |
1436 | { | |
1437 | struct wmt_thermal_ctrl_ops *p_des; | |
1438 | ||
1439 | wmt_tm_printk("[%s]\n", __func__); | |
1440 | ||
1441 | if (pg_wmt_tm) { | |
1442 | p_des = &pg_wmt_tm->wmt_if.ops; | |
1443 | p_des->query_temp = 0; | |
1444 | p_des->set_temp = 0; | |
1445 | ||
1446 | return 0; | |
1447 | } else { | |
1448 | return -1; | |
1449 | } | |
1450 | } | |
1451 | #endif | |
1452 | ||
1453 | static int __init wmt_tm_init(void) | |
1454 | { | |
1455 | int err = 0; | |
1456 | ||
1457 | wmt_tm_printk("[wmt_tm_init] start -->\n"); | |
1458 | ||
1459 | #if 0 | |
1460 | err = wmt_tm_ops_register(ops); | |
1461 | if(err) | |
1462 | return err; | |
1463 | #endif | |
1464 | ||
1465 | err = wmt_tm_proc_register(); | |
1466 | if(err) | |
1467 | return err; | |
1468 | ||
1469 | /* init a timer for stats tx bytes */ | |
1470 | wmt_stats_info.pre_time = 0; | |
1471 | wmt_stats_info.pre_tx_bytes = 0; | |
1472 | ||
1473 | init_timer(&wmt_stats_timer); | |
1474 | wmt_stats_timer.function = (void *)&wmt_cal_stats; | |
1475 | wmt_stats_timer.data = (unsigned long) &wmt_stats_info; | |
1476 | wmt_stats_timer.expires = jiffies + 1 * HZ; | |
1477 | add_timer(&wmt_stats_timer); | |
1478 | ||
1479 | #if 1 | |
1480 | err = wmt_tm_thz_cl_register(); | |
1481 | if(err) | |
1482 | return err; | |
1483 | #endif | |
1484 | wmt_tm_printk("[wmt_tm_init] end <--\n"); | |
1485 | ||
1486 | return 0; | |
1487 | } | |
1488 | ||
1489 | #if 0 | |
1490 | int wmt_tm_init_rt(void) | |
1491 | { | |
1492 | int err = 0; | |
1493 | ||
1494 | wmt_tm_printk("[wmt_tm_init_rt] start -->\n"); | |
1495 | ||
1496 | err = wmt_tm_thz_cl_register(); | |
1497 | if(err) | |
1498 | return err; | |
1499 | ||
1500 | wmt_tm_printk("[wmt_tm_init_rt] end <--\n"); | |
1501 | ||
1502 | return 0; | |
1503 | } | |
1504 | ||
1505 | int wmt_tm_deinit_rt(void) | |
1506 | { | |
1507 | int err = 0; | |
1508 | ||
1509 | wmt_tm_printk("[wmt_tm_deinit_rt] start -->\n"); | |
1510 | ||
1511 | err = wmt_tm_thz_cl_unregister(); | |
1512 | if(err) | |
1513 | return err; | |
1514 | ||
1515 | wmt_tm_printk("[wmt_tm_deinit_rt] end <--\n"); | |
1516 | ||
1517 | return 0; | |
1518 | } | |
1519 | #endif | |
1520 | ||
1521 | static void __exit wmt_tm_deinit(void) | |
1522 | { | |
1523 | int err = 0; | |
1524 | ||
1525 | wmt_tm_printk("[%s]\n", __func__); | |
1526 | #if 1 | |
1527 | err = wmt_tm_thz_cl_unregister(); | |
1528 | if(err) | |
1529 | return; | |
1530 | #endif | |
1531 | err = wmt_tm_proc_unregister(); | |
1532 | if(err) | |
1533 | return; | |
1534 | ||
1535 | #if 0 | |
1536 | err = wmt_tm_ops_unregister(); | |
1537 | if(err) | |
1538 | return; | |
1539 | #endif | |
1540 | ||
1541 | del_timer(&wmt_stats_timer); | |
1542 | ||
1543 | return; | |
1544 | } | |
1545 | module_init(wmt_tm_init); | |
1546 | module_exit(wmt_tm_deinit); | |
1547 |