123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504 |
- /* abc_spec_manager.c
- *
- * Abnormal Behavior Catcher's spec manager.
- *
- * Copyright 2021 Samsung Electronics
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- */
- #include <linux/sti/abc_spec_manager.h>
- #if IS_ENABLED(CONFIG_SEC_KUNIT)
- #include <linux/sti/abc_kunit.h>
- #endif
- struct list_head abc_spec_list;
- EXPORT_SYMBOL_KUNIT(abc_spec_list);
- struct abc_event_group_struct abc_event_group_list[] = {
- {ABC_GROUP_CAMERA_MIPI_ERROR_ALL, "camera", "mipi_error_all"},
- };
- #if IS_ENABLED(CONFIG_OF)
- int abc_parse_dt(struct device *dev)
- {
- struct abc_platform_data *pdata = dev->platform_data;
- struct spec_data_type1 *spec_type1;
- struct device_node *np;
- struct device_node *type1_np;
- int idx, rc;
- np = dev->of_node;
- pdata->nItem = of_get_child_count(np);
- if (!pdata->nItem) {
- dev_err(dev, "There are no items");
- return -ENODEV;
- }
- /* spec_type_1 */
- type1_np = of_find_node_by_name(np, "abc_spec_type1");
- rc = of_property_count_strings(type1_np, ERROR_KEY);
- INIT_LIST_HEAD(&abc_spec_list);
- for (idx = 0; idx < rc; idx++) {
- spec_type1 = devm_kzalloc(dev, sizeof(struct spec_data_type1), GFP_KERNEL);
- if (!spec_type1)
- return -ENOMEM;
- if (abc_parse_dt_type1(dev, type1_np, idx, spec_type1)) {
- ABC_PRINT("failed parse dt spec_type1 idx : %d", idx);
- continue;
- }
- list_add_tail(&spec_type1->node, &abc_spec_list);
- }
- return 0;
- }
- #endif
- int sec_abc_get_normal_token_value(char *dst, char *src, char *token)
- {
- int token_len = strlen(token);
- if (strncmp(src, token, token_len) || !*(src + token_len)) {
- ABC_DEBUG("Invalid input : src-%s, token-%s", src, token);
- return -EINVAL;
- }
- strlcpy(dst, src + token_len, ABC_EVENT_STR_MAX);
- return 0;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_normal_token_value);
- int sec_abc_get_event_module(char *dst, char *src)
- {
- return sec_abc_get_normal_token_value(dst, src, "MODULE=");
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_event_module);
- int sec_abc_get_ext_log(char *dst, char *src)
- {
- return sec_abc_get_normal_token_value(dst, src, "EXT_LOG=");
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_ext_log);
- int sec_abc_get_event_name(char *dst, char *src)
- {
- int ret_info = 0, ret_warn = 0;
- ret_info = sec_abc_get_normal_token_value(dst, src, "INFO=");
- ret_warn = sec_abc_get_normal_token_value(dst, src, "WARN=");
- return (ret_info & ret_warn) ? -EINVAL : 0;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_event_name);
- int sec_abc_get_event_type(char *dst, char *src)
- {
- if (strncmp(src, "WARN", 4) && strncmp(src, "INFO", 4)) {
- ABC_PRINT("Invalid input : %s", src);
- return -EINVAL;
- }
- strlcpy(dst, src, 5);
- return 0;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_event_type);
- int sec_abc_get_count(int *dst, char *src)
- {
- if (strncmp(src, "COUNT=", 6) || !*(src + 6)) {
- ABC_PRINT("Invalid input : %s", src);
- return -EINVAL;
- }
- if (!strncmp(src + 6, "DEFAULT", 7)) {
- *dst = ABC_DEFAULT_COUNT;
- return 0;
- }
- if (kstrtoint(src + 6, 0, dst) || *dst <= 0 || *dst > ABC_EVENT_BUFFER_MAX) {
- ABC_PRINT("Invalid input : %s", src);
- return -EINVAL;
- }
- return 0;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_count);
- unsigned int sec_abc_get_ktime_ms(void)
- {
- u64 ktime;
- /* Calculate current kernel time */
- ktime = local_clock();
- do_div(ktime, NSEC_PER_MSEC);
- return (unsigned int)ktime;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_ktime_ms);
- int sec_abc_make_key_data(struct abc_key_data *key_data, char *str)
- {
- char *event_strings[ABC_UEVENT_MAX] = {0,};
- char temp[ABC_BUFFER_MAX];
- char *c, *p;
- int idx = 0, i;
- ABC_DEBUG("start : %s", str);
- strlcpy(temp, str, ABC_BUFFER_MAX);
- p = temp;
- while ((c = strsep(&p, "@")) != NULL && idx < ABC_UEVENT_MAX) {
- event_strings[idx] = c;
- idx++;
- }
- if (idx >= ABC_UEVENT_MAX)
- return -EINVAL;
- if (sec_abc_get_event_module(key_data->event_module, event_strings[0]))
- return -EINVAL;
- if (sec_abc_get_event_name(key_data->event_name, event_strings[1]))
- return -EINVAL;
- if (sec_abc_get_event_type(key_data->event_type, event_strings[1]))
- return -EINVAL;
- for (i = 2; i < idx; i++) {
- if (!strncmp(event_strings[i], "EXT_LOG=", 8)) {
- if (sec_abc_get_ext_log(key_data->ext_log, event_strings[i]))
- return -EINVAL;
- } else
- return -EINVAL;
- }
- key_data->cur_time = sec_abc_get_ktime_ms();
- ABC_DEBUG("Module(%s) Level(%s) Event(%s) EXT_LOG(%s) cur_time(%d)",
- key_data->event_module,
- key_data->event_type,
- key_data->event_name,
- key_data->ext_log,
- key_data->cur_time);
- return 0;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_make_key_data);
- struct abc_common_spec_data *sec_abc_get_matched_common_spec(char *module_name, char *error_name)
- {
- return sec_abc_get_matched_common_spec_type1(module_name, error_name);
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_matched_common_spec);
- int sec_abc_get_buffer_size_from_threshold_cnt(int threshold_cnt)
- {
- int i, min_buffer_size = 16;
- for (i = 1; i < threshold_cnt; i *= 2)
- ;
- return min_buffer_size > i ? min_buffer_size : i;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_buffer_size_from_threshold_cnt);
- void sec_abc_enqueue_event_data(struct abc_key_data *key_data)
- {
- struct abc_common_spec_data *common_spec = NULL;
- common_spec = sec_abc_get_matched_common_spec(key_data->event_module, key_data->event_name);
- if (!common_spec || !strcmp(key_data->event_type, "INFO")) {
- ABC_PRINT_KUNIT("There is no matched buffer");
- } else {
- ABC_DEBUG_KUNIT("There is a matched buffer. Enqueue data");
- sec_abc_enqueue_event_data_type1(common_spec, key_data->cur_time);
- }
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_enqueue_event_data);
- void sec_abc_reset_event_buffer(struct abc_key_data *key_data)
- {
- struct abc_common_spec_data *common_spec;
- struct spec_data_type1 *spec_type1;
- common_spec = sec_abc_get_matched_common_spec(key_data->event_module, key_data->event_name);
- if (!common_spec || !strcmp(key_data->event_type, "INFO")) {
- ABC_PRINT_KUNIT("There is no matched buffer");
- } else {
- ABC_PRINT_KUNIT("There is a matched buffer. Reset buffer");
- spec_type1 = container_of(common_spec, struct spec_data_type1, common_spec);
- sec_abc_reset_buffer_type1(spec_type1);
- }
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_reset_event_buffer);
- bool sec_abc_reached_spec(struct abc_key_data *key_data)
- {
- struct abc_common_spec_data *common_spec;
- if (!strcmp(key_data->event_type, "INFO")) {
- ABC_PRINT("INFO doesn't have spec");
- return false;
- }
- common_spec = sec_abc_get_matched_common_spec(key_data->event_module, key_data->event_name);
- if (!common_spec)
- return true;
- return sec_abc_reached_spec_type1(common_spec, key_data->cur_time);
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_reached_spec);
- int sec_abc_parse_spec_cmd(char *str, struct abc_spec_cmd *abc_spec)
- {
- int idx = 0;
- char temp[ABC_BUFFER_MAX];
- char *c, *p;
- char *sys_input_strings[3] = { 0, };
- strlcpy(temp, str, ABC_BUFFER_MAX);
- p = temp;
- while ((c = strsep(&p, "@")) != NULL && idx < ABC_SPEC_CMD_STR_MAX) {
- sys_input_strings[idx] = c;
- idx++;
- }
- if (idx != ABC_SPEC_CMD_STR_MAX)
- return -EINVAL;
- if (sec_abc_get_event_module(abc_spec->module, sys_input_strings[0]))
- return -EINVAL;
- if (sec_abc_get_event_name(abc_spec->name, sys_input_strings[1]))
- return -EINVAL;
- strlcpy(abc_spec->spec, sys_input_strings[2], ABC_EVENT_STR_MAX);
- return 0;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_parse_spec_cmd);
- int sec_abc_apply_changed_spec(char *module_name, char *error_name, char *spec)
- {
- struct abc_common_spec_data *common_spec;
- struct spec_data_type1 *spec_type1;
- int idx = 0, count = 0;
- ABC_PRINT("start : %s %s %s", module_name, error_name, spec);
- idx = sec_abc_get_idx_of_registered_event(module_name, error_name);
- if (idx < 0)
- return -EINVAL;
- if (!strcmp(spec, "OFF")) {
- abc_event_list[idx].enabled = false;
- return 0;
- }
- if (sec_abc_get_count(&count, spec))
- return -EINVAL;
- if (abc_event_list[idx].singular_spec) {
- if (count == ABC_DEFAULT_COUNT) {
- abc_event_list[idx].enabled = true;
- return 0;
- } else
- return -EINVAL;
- }
- common_spec = sec_abc_get_matched_common_spec(module_name, error_name);
- if (!common_spec)
- return -EINVAL;
- abc_event_list[idx].enabled = false;
- spec_type1 = container_of(common_spec, struct spec_data_type1, common_spec);
- if (count == ABC_DEFAULT_COUNT)
- count = spec_type1->default_count;
- spec_type1->threshold_cnt = count;
- spec_type1->buffer.size = count + 1;
- if (abc_alloc_memory_to_buffer_type1(spec_type1, spec_type1->buffer.size))
- return -ENOMEM;
- sec_abc_reset_buffer_type1(spec_type1);
- abc_event_list[idx].enabled = true;
- ABC_PRINT("MODULE(%s) ERROR(%s) COUNT(%d) TIME(%d) Enabled(%d)",
- common_spec->module_name,
- common_spec->error_name,
- spec_type1->threshold_cnt,
- spec_type1->threshold_time,
- abc_event_list[idx].enabled);
- return 0;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_apply_changed_spec);
- enum abc_event_group sec_abc_get_group(char *module, char *name)
- {
- int idx = 0;
- for (idx = 0; idx < ARRAY_SIZE(abc_event_group_list); idx++) {
- if (strcmp(module, abc_event_group_list[idx].module) == 0 &&
- strcmp(name, abc_event_group_list[idx].name) == 0) {
- return abc_event_group_list[idx].group;
- }
- }
- return ABC_GROUP_NONE;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_get_group);
- int sec_abc_apply_changed_group_spec(enum abc_event_group group, char *spec)
- {
- int idx = 0;
- ABC_PRINT("start : %d %s", group, spec);
- for (idx = 0; idx < REGISTERED_ABC_EVENT_TOTAL; idx++) {
- if (group == abc_event_list[idx].group) {
- if (sec_abc_apply_changed_spec(abc_event_list[idx].module_name,
- abc_event_list[idx].error_name, spec)) {
- return -EINVAL;
- }
- }
- }
- return 0;
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_apply_changed_group_spec);
- void sec_abc_change_spec(const char *str)
- {
- char *cmd_string, *p;
- char temp[ABC_BUFFER_MAX * 5];
- int cnt = 0;
- enum abc_event_group group;
- struct abc_spec_cmd abc_spec;
- ABC_PRINT("start : %s", str);
- if (!strncmp(str, "reset", 5)) {
- sec_abc_reset_all_spec();
- ABC_PRINT("end : %s", str);
- return;
- }
- strlcpy(temp, str, ABC_BUFFER_MAX * 5);
- p = temp;
- while ((cmd_string = strsep(&p, ",\n")) != NULL && cnt < REGISTERED_ABC_EVENT_TOTAL) {
- cnt++;
- if (!cmd_string[0])
- continue;
- if (sec_abc_parse_spec_cmd(cmd_string, &abc_spec)) {
- ABC_PRINT_KUNIT("Invalid change cmd. Check the Input");
- break;
- }
- group = sec_abc_get_group(abc_spec.module, abc_spec.name);
- if (group == ABC_GROUP_NONE) {
- if (sec_abc_apply_changed_spec(abc_spec.module, abc_spec.name, abc_spec.spec)) {
- ABC_PRINT_KUNIT("Invalid change cmd. Check the Input");
- break;
- }
- } else {
- if (sec_abc_apply_changed_group_spec(group, abc_spec.spec)) {
- ABC_PRINT_KUNIT("Invalid change cmd. Check the Input");
- break;
- }
- }
- }
- }
- void sec_abc_reset_all_buffer(void)
- {
- struct spec_data_type1 *spec_type1;
- list_for_each_entry(spec_type1, &abc_spec_list, node) {
- sec_abc_reset_buffer_type1(spec_type1);
- }
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_reset_all_buffer);
- void sec_abc_reset_all_spec(void)
- {
- struct spec_data_type1 *spec_type1;
- list_for_each_entry(spec_type1, &abc_spec_list, node) {
- spec_type1->threshold_cnt = spec_type1->default_count;
- spec_type1->buffer.size = spec_type1->threshold_cnt + 1;
- abc_event_list[spec_type1->common_spec.idx].enabled = spec_type1->default_enabled;
- sec_abc_reset_buffer_type1(spec_type1);
- }
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_reset_all_spec);
- int sec_abc_read_spec(char *buf)
- {
- struct spec_data_type1 *spec_type1;
- int len = 0, idx;
- len += scnprintf(buf + len, PAGE_SIZE - len, "spec type1\n");
- list_for_each_entry(spec_type1, &abc_spec_list, node) {
- len += scnprintf(buf + len, PAGE_SIZE - len, "MODULE=%s ",
- spec_type1->common_spec.module_name);
- len += scnprintf(buf + len, PAGE_SIZE - len, "WARN=%s ",
- spec_type1->common_spec.error_name);
- len += scnprintf(buf + len, PAGE_SIZE - len, "THRESHOLD_CNT=%d ",
- spec_type1->threshold_cnt);
- len += scnprintf(buf + len, PAGE_SIZE - len, "THRESHOLD_TIME=%d ",
- spec_type1->threshold_time);
- idx = spec_type1->common_spec.idx;
- len += scnprintf(buf + len, PAGE_SIZE - len, "ENABLE=%s",
- ((abc_event_list[idx].enabled) ? "ON" : "OFF"));
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- }
- for (idx = 0; idx < ARRAY_SIZE(abc_event_group_list); idx++) {
- len += scnprintf(buf + len, PAGE_SIZE - len, "MODULE=%s ",
- abc_event_group_list[idx].module);
- len += scnprintf(buf + len, PAGE_SIZE - len, "WARN=%s ",
- abc_event_group_list[idx].name);
- len += scnprintf(buf + len, PAGE_SIZE - len, "THRESHOLD_CNT=group ");
- len += scnprintf(buf + len, PAGE_SIZE - len, "THRESHOLD_TIME=group ");
- len += scnprintf(buf + len, PAGE_SIZE - len, "ENABLE=group");
- len += scnprintf(buf + len, PAGE_SIZE - len, "\n");
- }
- ABC_PRINT("%d", len);
- return len;
- }
- void sec_abc_free_spec_buffer(void)
- {
- struct spec_data_type1 *spec_buf;
- list_for_each_entry(spec_buf, &abc_spec_list, node) {
- kfree(spec_buf->buffer.abc_element);
- spec_buf->buffer.abc_element = NULL;
- spec_buf->buffer.buffer_max = 0;
- }
- }
- EXPORT_SYMBOL_KUNIT(sec_abc_free_spec_buffer);
- MODULE_DESCRIPTION("Samsung ABC Driver's spec manager");
- MODULE_AUTHOR("Samsung Electronics");
- MODULE_LICENSE("GPL");
|