3 * Abnormal Behavior Catcher Common Driver
5 * Copyright (C) 2017 Samsung Electronics
7 * Hyeokseon Yu <hyeokseon.yu@samsung.com>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
20 #include <linux/sti/abc_common.h>
23 // #define ABC_WARNING_REPORT
25 static struct device
*sec_abc
;
26 static int abc_enabled
;
29 #define ABC_PRINT(format, ...) pr_info("[sec_abc] " format, ##__VA_ARGS__)
32 static int parse_gpu_data(struct device
*dev
,
33 struct abc_platform_data
*pdata
,
34 struct device_node
*np
)
36 struct abc_qdata
*cgpu
;
38 cgpu
= pdata
->gpu_items
;
39 cgpu
->desc
= of_get_property(np
, "gpu,label", NULL
);
41 if (of_property_read_u32(np
, "gpu,threshold_count", &cgpu
->threshold_cnt
)) {
42 dev_err(dev
, "Failed to get gpu threshold count: node not exist\n");
46 if (of_property_read_u32(np
, "gpu,threshold_time", &cgpu
->threshold_time
)) {
47 dev_err(dev
, "Failed to get gpu threshold time: node not exist\n");
51 cgpu
->buffer
.abc_element
= kzalloc(sizeof(cgpu
->buffer
.abc_element
[0]) * (cgpu
->threshold_cnt
+ 1), GFP_KERNEL
);
53 if (!cgpu
->buffer
.abc_element
)
56 cgpu
->buffer
.size
= cgpu
->threshold_cnt
+ 1;
57 cgpu
->buffer
.rear
= 0;
58 cgpu
->buffer
.front
= 0;
64 static int parse_aicl_data(struct device
*dev
,
65 struct abc_platform_data
*pdata
,
66 struct device_node
*np
)
68 struct abc_qdata
*caicl
;
70 caicl
= pdata
->aicl_items
;
71 caicl
->desc
= of_get_property(np
, "aicl,label", NULL
);
73 if (of_property_read_u32(np
, "aicl,threshold_count", &caicl
->threshold_cnt
)) {
74 dev_err(dev
, "Failed to get aicl threshold count: node not exist\n");
78 if (of_property_read_u32(np
, "aicl,threshold_time", &caicl
->threshold_time
)) {
79 dev_err(dev
, "Failed to get aicl threshold time: node not exist\n");
83 caicl
->buffer
.abc_element
= kzalloc(sizeof(caicl
->buffer
.abc_element
[0]) *
84 (caicl
->threshold_cnt
+ 1), GFP_KERNEL
);
86 if (!caicl
->buffer
.abc_element
)
89 caicl
->buffer
.size
= caicl
->threshold_cnt
+ 1;
90 caicl
->buffer
.rear
= 0;
91 caicl
->buffer
.front
= 0;
97 static int abc_parse_dt(struct device
*dev
)
99 struct abc_platform_data
*pdata
= dev
->platform_data
;
100 struct device_node
*np
;
101 struct device_node
*gpu_np
;
102 struct device_node
*aicl_np
;
105 pdata
->nItem
= of_get_child_count(np
);
107 dev_err(dev
, "There are no items\n");
111 gpu_np
= of_find_node_by_name(np
, "gpu");
112 pdata
->nGpu
= of_get_child_count(gpu_np
);
113 pdata
->gpu_items
= devm_kzalloc(dev
,
114 sizeof(struct abc_qdata
), GFP_KERNEL
);
116 if (!pdata
->gpu_items
) {
117 dev_err(dev
, "Failed to allocate GPU memory\n");
122 parse_gpu_data(dev
, pdata
, gpu_np
);
124 aicl_np
= of_find_node_by_name(np
, "aicl");
125 pdata
->nAicl
= of_get_child_count(aicl_np
);
126 pdata
->aicl_items
= devm_kzalloc(dev
,
127 sizeof(struct abc_qdata
), GFP_KERNEL
);
129 if (!pdata
->aicl_items
) {
130 dev_err(dev
, "Failed to allocate AICL memory\n");
135 parse_aicl_data(dev
, pdata
, aicl_np
);
142 static const struct of_device_id sec_abc_dt_match
[] = {
143 { .compatible
= "samsung,sec_abc" },
148 static int sec_abc_resume(struct device
*dev
)
153 static int sec_abc_remove(struct platform_device
*pdev
)
158 static const struct dev_pm_ops sec_abc_pm
= {
159 .resume
= sec_abc_resume
,
162 static void sec_abc_reset_gpu_buffer(void)
164 struct abc_info
*pinfo
= dev_get_drvdata(sec_abc
);
166 pinfo
->pdata
->gpu_items
->buffer
.rear
= 0;
167 pinfo
->pdata
->gpu_items
->buffer
.front
= 0;
168 pinfo
->pdata
->gpu_items
->fail_cnt
= 0;
171 static void sec_abc_reset_aicl_buffer(void)
173 struct abc_info
*pinfo
= dev_get_drvdata(sec_abc
);
175 pinfo
->pdata
->aicl_items
->buffer
.rear
= 0;
176 pinfo
->pdata
->aicl_items
->buffer
.front
= 0;
177 pinfo
->pdata
->aicl_items
->fail_cnt
= 0;
180 static ssize_t
store_abc_enabled(struct device
*dev
,
181 struct device_attribute
*attr
,
182 const char *buf
, size_t count
)
184 struct abc_info
*pinfo
= dev_get_drvdata(sec_abc
);
186 if (!strncmp(buf
, "1", 1)) {
187 ABC_PRINT("ABC driver enabled.\n");
188 abc_enabled
= ABC_TYPE1_ENABLED
;
189 complete(&pinfo
->enable_done
);
190 } else if (!strncmp(buf
, "2", 1)) {
191 ABC_PRINT("Common driver enabled.\n");
192 abc_enabled
= ABC_TYPE2_ENABLED
;
193 complete(&pinfo
->enable_done
);
194 } else if (!strncmp(buf
, "0", 1)) {
195 ABC_PRINT("ABC/Common driver disabled.\n");
196 if (abc_enabled
== ABC_TYPE1_ENABLED
) {
197 sec_abc_reset_gpu_buffer();
198 sec_abc_reset_aicl_buffer();
201 abc_enabled
= ABC_DISABLED
;
206 static ssize_t
show_abc_enabled(struct device
*dev
,
207 struct device_attribute
*attr
,
210 return sprintf(buf
, "%d\n", abc_enabled
);
212 static DEVICE_ATTR(enabled
, 0644, show_abc_enabled
, store_abc_enabled
);
214 /* reset abc log_list */
215 static ssize_t
store_abc_log(struct device
*dev
,
216 struct device_attribute
*attr
,
217 const char *buf
, size_t count
)
219 struct abc_info
*pinfo
= dev_get_drvdata(sec_abc
);
220 struct abc_log_entry
*abc_log
;
222 pinfo
->log_list_cnt
= 0;
224 while (!list_empty(&pinfo
->log_list
)) {
225 abc_log
= list_first_entry(&pinfo
->log_list
, struct abc_log_entry
, node
);
226 list_del(&abc_log
->node
);
233 /* read abc log_list */
234 static ssize_t
show_abc_log(struct device
*dev
,
235 struct device_attribute
*attr
,
238 struct abc_info
*pinfo
= dev_get_drvdata(sec_abc
);
239 struct abc_log_entry
*abc_log
;
242 list_for_each_entry(abc_log
, &pinfo
->log_list
, node
) {
243 count
+= sprintf(buf
+ count
, "%s\n", abc_log
->abc_log_str
);
248 static DEVICE_ATTR(log
, 0644, show_abc_log
, store_abc_log
);
250 static int sec_abc_is_full(struct abc_buffer
*buffer
)
252 if ((buffer
->rear
+ 1) % buffer
->size
== buffer
->front
)
258 static int sec_abc_is_empty(struct abc_buffer
*buffer
)
260 if (buffer
->front
== buffer
->rear
)
266 static void sec_abc_enqueue(struct abc_buffer
*buffer
, struct abc_fault_info in
)
268 if (sec_abc_is_full(buffer
)) {
269 ABC_PRINT("queue is full.\n");
271 buffer
->rear
= (buffer
->rear
+ 1) % buffer
->size
;
272 buffer
->abc_element
[buffer
->rear
] = in
;
276 static void sec_abc_dequeue(struct abc_buffer
*buffer
, struct abc_fault_info
*out
)
278 if (sec_abc_is_empty(buffer
)) {
279 ABC_PRINT("queue is empty.\n");
281 buffer
->front
= (buffer
->front
+ 1) % buffer
->size
;
282 *out
= buffer
->abc_element
[buffer
->front
];
286 static int sec_abc_get_diff_time(struct abc_buffer
*buffer
)
288 int front_time
, rear_time
;
290 front_time
= buffer
->abc_element
[(buffer
->front
+ 1) % buffer
->size
].cur_time
;
291 rear_time
= buffer
->abc_element
[buffer
->rear
].cur_time
;
293 ABC_PRINT("front time : %d(%d) rear_time %d(%d) diff : %d\n",
298 rear_time
- front_time
);
300 return rear_time
- front_time
;
303 int sec_abc_get_enabled(void)
307 EXPORT_SYMBOL(sec_abc_get_enabled
);
309 static void sec_abc_work_func(struct work_struct
*work
)
311 struct abc_info
*pinfo
= container_of(work
, struct abc_info
, work
);
312 struct abc_qdata
*pgpu
, *paicl
;
313 struct abc_fault_info in
, out
;
314 struct abc_log_entry
*abc_log
;
318 unsigned long local_time
;
321 char *uevent_str
[ABC_UEVENT_MAX
] = {0,};
322 char temp
[ABC_BUFFER_MAX
], timestamp
[ABC_BUFFER_MAX
], event_type
[ABC_BUFFER_MAX
];
325 unsigned long ktime_ms
;
328 strcpy(temp
, pinfo
->abc_str
);
331 /* Caculate current kernel time */
332 ktime
= local_clock();
333 ktime_ms
= ktime
/ NSEC_PER_MSEC
;
334 ktime_rem
= do_div(ktime
, NSEC_PER_SEC
);
336 /* Caculate current local time */
338 local_time
= (u32
)(ts
.tv_sec
- (sys_tz
.tz_minuteswest
* 60));
339 rtc_time_to_tm(local_time
, &tm
);
341 /* Parse uevent string */
342 while ((c
= strsep(&p
, "@")) != NULL
) {
346 sprintf(timestamp
, "TIMESTAMP=%lu", ktime_ms
);
347 uevent_str
[idx
++] = ×tamp
[0];
348 uevent_str
[idx
] = '\0';
349 strlcpy(event_type
, uevent_str
[1] + 6, sizeof(event_type
));
351 ABC_PRINT("event type : %s\n", event_type
);
353 #if defined(DEBUG_ABC)
355 while ((c
= uevent_str
[idx
]) != '\0') {
356 ABC_PRINT("%s\n", uevent_str
[idx
]);
361 /* Add abc log_list */
362 abc_log
= kzalloc(sizeof(*abc_log
), GFP_KERNEL
);
364 snprintf(abc_log
->abc_log_str
, ABC_LOG_STR_LEN
, "[%5lu.%03d][%02d:%02d:%02d.%03lu]%s_%s",
365 (unsigned long)ktime
, (int)(ktime_rem
/ NSEC_PER_MSEC
), tm
.tm_hour
, tm
.tm_min
,
366 tm
.tm_sec
, ts
.tv_nsec
/ 1000000, uevent_str
[0] + 7, uevent_str
[1] + 6);
367 if (pinfo
->log_list_cnt
< ABC_LOG_MAX
) {
368 list_add_tail(&abc_log
->node
, &pinfo
->log_list
);
369 pinfo
->log_list_cnt
++;
371 list_add_tail(&abc_log
->node
, &pinfo
->log_list
);
372 abc_log
= list_first_entry(&pinfo
->log_list
, struct abc_log_entry
, node
);
373 list_del(&abc_log
->node
);
377 ABC_PRINT("failed to allocate abc_log\n");
380 if (abc_enabled
== ABC_TYPE1_ENABLED
) {
381 pgpu
= pinfo
->pdata
->gpu_items
;
382 paicl
= pinfo
->pdata
->aicl_items
;
385 if (!strncasecmp(event_type
, "gpu_fault", 9)) {
386 in
.cur_time
= (unsigned long)ktime
/ USEC_PER_SEC
;
387 in
.cur_cnt
= pgpu
->fail_cnt
++;
389 ABC_PRINT("gpu fail count : %d\n", pgpu
->fail_cnt
);
390 sec_abc_enqueue(&pgpu
->buffer
, in
);
392 /* Check gpu fault */
393 /* Case 1 : Over threshold count */
394 if (pgpu
->fail_cnt
>= pgpu
->threshold_cnt
) {
395 if (sec_abc_get_diff_time(&pgpu
->buffer
) < pgpu
->threshold_time
) {
396 ABC_PRINT("GPU fault occurred. Send uevent.\n");
397 kobject_uevent_env(&sec_abc
->kobj
, KOBJ_CHANGE
, uevent_str
);
400 sec_abc_dequeue(&pgpu
->buffer
, &out
);
401 ABC_PRINT("cur_time : %lu cur_cnt : %d\n", out
.cur_time
, out
.cur_cnt
);
402 /* Case 2 : Check front and rear node in queue. Because it's occurred within max count */
403 } else if (sec_abc_is_full(&pgpu
->buffer
)) {
404 if (sec_abc_get_diff_time(&pgpu
->buffer
) < pgpu
->threshold_time
) {
405 ABC_PRINT("GPU fault occurred. Send uevent.\n");
406 kobject_uevent_env(&sec_abc
->kobj
, KOBJ_CHANGE
, uevent_str
);
408 sec_abc_dequeue(&pgpu
->buffer
, &out
);
409 ABC_PRINT("cur_time : %lu cur_cnt : %d\n", out
.cur_time
, out
.cur_cnt
);
412 #ifdef ABC_WARNING_REPORT
413 /* Send GPU fault warning */
414 strcat(uevent_str
[1], "_w");
415 kobject_uevent_env(&sec_abc
->kobj
, KOBJ_CHANGE
, uevent_str
);
417 } else if (!strncasecmp(event_type
, "aicl", 4)) { /* AICL fault */
418 in
.cur_time
= (unsigned long)ktime
/ USEC_PER_SEC
;
419 in
.cur_cnt
= paicl
->fail_cnt
++;
421 ABC_PRINT("aicl fail count : %d\n", paicl
->fail_cnt
);
422 sec_abc_enqueue(&paicl
->buffer
, in
);
424 /* Check aicl fault */
425 if (paicl
->fail_cnt
>= paicl
->threshold_cnt
) {
426 if (sec_abc_get_diff_time(&paicl
->buffer
) < paicl
->threshold_time
) {
427 ABC_PRINT("AICL fault occurred. Send uevent.\n");
428 kobject_uevent_env(&sec_abc
->kobj
, KOBJ_CHANGE
, uevent_str
);
429 while (!sec_abc_is_empty(&paicl
->buffer
))
430 sec_abc_dequeue(&paicl
->buffer
, &out
);
434 sec_abc_dequeue(&paicl
->buffer
, &out
);
435 ABC_PRINT("cur_time : %lu cur_cnt : %d\n", out
.cur_time
, out
.cur_cnt
);
440 kobject_uevent_env(&sec_abc
->kobj
, KOBJ_CHANGE
, uevent_str
);
441 ABC_PRINT("Send uevent.\n");
443 } else { /* ABC_TYPE2_ENABLED */
444 kobject_uevent_env(&sec_abc
->kobj
, KOBJ_CHANGE
, uevent_str
);
445 ABC_PRINT("Send uevent.\n");
449 /* event string format
451 * ex) MODULE=tsp@ERROR=power_status_mismatch
452 * MODULE=tsp@ERROR=power_status_mismatch@EXT_LOG=fw_ver(0108)
455 void sec_abc_send_event(char *str
)
457 struct abc_info
*pinfo
;
460 ABC_PRINT("ABC driver is not initialized!\n");
464 if (abc_enabled
== ABC_DISABLED
) {
465 ABC_PRINT("ABC is disabled!\n");
469 pinfo
= dev_get_drvdata(sec_abc
);
471 strlcpy(pinfo
->abc_str
, str
, sizeof(pinfo
->abc_str
));
472 queue_work(pinfo
->workqueue
, &pinfo
->work
);
474 EXPORT_SYMBOL(sec_abc_send_event
);
477 * sec_abc_wait_enable() - wait for abc enable done
478 * Return : 0 for success, -1 for fail(timeout or abc not initialized)
480 int sec_abc_wait_enabled(void)
482 struct abc_info
*pinfo
;
483 unsigned long timeout
;
486 ABC_PRINT("ABC driver is not initialized!\n");
493 pinfo
= dev_get_drvdata(sec_abc
);
495 reinit_completion(&pinfo
->enable_done
);
497 timeout
= wait_for_completion_timeout(&pinfo
->enable_done
,
498 msecs_to_jiffies(ABC_WAIT_ENABLE_TIMEOUT
));
501 ABC_PRINT("%s : timeout!\n", __func__
);
507 EXPORT_SYMBOL(sec_abc_wait_enabled
);
509 static int sec_abc_probe(struct platform_device
*pdev
)
511 struct abc_platform_data
*pdata
;
512 struct abc_info
*pinfo
;
515 ABC_PRINT("%s\n", __func__
);
519 if (pdev
->dev
.of_node
) {
520 pdata
= devm_kzalloc(&pdev
->dev
,
521 sizeof(struct abc_platform_data
), GFP_KERNEL
);
524 dev_err(&pdev
->dev
, "Failed to allocate platform data\n");
528 pdev
->dev
.platform_data
= pdata
;
529 ret
= abc_parse_dt(&pdev
->dev
);
531 dev_err(&pdev
->dev
, "Failed to parse dt data\n");
535 pr_info("%s: parse dt done\n", __func__
);
537 pdata
= pdev
->dev
.platform_data
;
541 dev_err(&pdev
->dev
, "There are no platform data\n");
545 pinfo
= kzalloc(sizeof(*pinfo
), GFP_KERNEL
);
550 pinfo
->dev
= sec_device_create(pinfo
, "sec_abc");
551 if (IS_ERR(pinfo
->dev
)) {
552 pr_err("%s Failed to create device(sec_abc)!\n", __func__
);
557 ret
= device_create_file(pinfo
->dev
, &dev_attr_enabled
);
559 pr_err("%s: Failed to create device enabled file\n", __func__
);
560 goto err_create_abc_enabled_sysfs
;
563 ret
= device_create_file(pinfo
->dev
, &dev_attr_log
);
565 pr_err("%s: Failed to create device log file\n", __func__
);
566 goto err_create_abc_log_sysfs
;
569 INIT_WORK(&pinfo
->work
, sec_abc_work_func
);
571 pinfo
->workqueue
= create_singlethread_workqueue("sec_abc_wq");
572 if (!pinfo
->workqueue
)
573 goto err_create_abc_wq
;
575 INIT_LIST_HEAD(&pinfo
->log_list
);
576 pinfo
->log_list_cnt
= 0;
578 init_completion(&pinfo
->enable_done
);
580 sec_abc
= pinfo
->dev
;
581 pinfo
->pdata
= pdata
;
583 platform_set_drvdata(pdev
, pinfo
);
588 device_remove_file(pinfo
->dev
, &dev_attr_log
);
589 err_create_abc_log_sysfs
:
590 device_remove_file(pinfo
->dev
, &dev_attr_enabled
);
591 err_create_abc_enabled_sysfs
:
592 sec_device_destroy(sec_abc
->devt
);
600 static struct platform_driver sec_abc_driver
= {
601 .probe
= sec_abc_probe
,
602 .remove
= sec_abc_remove
,
605 .owner
= THIS_MODULE
,
606 #if defined(CONFIG_PM)
610 .of_match_table
= of_match_ptr(sec_abc_dt_match
),
615 static int __init
sec_abc_init(void)
617 ABC_PRINT("%s\n", __func__
);
619 return platform_driver_register(&sec_abc_driver
);
622 static void __exit
sec_abc_exit(void)
624 return platform_driver_unregister(&sec_abc_driver
);
627 module_init(sec_abc_init
);
628 module_exit(sec_abc_exit
);
630 MODULE_DESCRIPTION("Samsung ABC Driver");
631 MODULE_AUTHOR("Samsung Electronics");
632 MODULE_LICENSE("GPL");