| // SPDX-License-Identifier: (GPL-2.0+ OR MIT) |
| /* |
| * Copyright (c) 2019 Amlogic, Inc. All rights reserved. |
| */ |
| |
| #include <linux/module.h> |
| |
| #include <trace/events/meson_atrace.h> |
| #include <linux/device/class.h> |
| |
| static u64 atrace_tag; |
| |
| #define TAG_INFO(name) \ |
| { #name, KERNEL_ATRACE_TAG_ ## name } |
| |
| struct { |
| char *name; |
| int tag; |
| } tag_info[] = { |
| TAG_INFO(VIDEO), |
| TAG_INFO(CODEC_MM), |
| TAG_INFO(VDEC), |
| TAG_INFO(TSYNC), |
| TAG_INFO(IONVIDEO), |
| TAG_INFO(AMLVIDEO), |
| TAG_INFO(VIDEO_COMPOSER), |
| TAG_INFO(V4L2), |
| TAG_INFO(CPUFREQ), |
| TAG_INFO(MSYNC), |
| TAG_INFO(DEMUX), |
| TAG_INFO(MEDIA_SYNC), |
| TAG_INFO(DDR_BW), |
| TAG_INFO(DIM), |
| { NULL, 0 } |
| }; |
| |
| int get_atrace_tag_enabled(unsigned short tag) |
| { |
| if (tag == KERNEL_ATRACE_TAG_ALL) |
| return 1; |
| return atrace_tag & (1 << tag); |
| } |
| EXPORT_SYMBOL(get_atrace_tag_enabled); |
| |
| void set_atrace_tag_enabled(unsigned short tag, int enable) |
| { |
| if (enable) |
| atrace_tag |= (u64)1 << tag; |
| else |
| atrace_tag &= ~((u64)1 << tag); |
| } |
| EXPORT_SYMBOL(set_atrace_tag_enabled); |
| |
| static ssize_t show_atrace_tag(struct class *class, |
| struct class_attribute *attr, char *buf) |
| { |
| ssize_t size = 0; |
| int i; |
| |
| for (i = 0; i < ARRAY_SIZE(tag_info) && tag_info[i].name; i++) { |
| size += sprintf(buf + size, "%2d %s %s\n", |
| tag_info[i].tag, tag_info[i].name, |
| get_atrace_tag_enabled(tag_info[i].tag) ? "ON" : "OFF"); |
| } |
| |
| return size; |
| } |
| |
| static ssize_t store_atrace_tag(struct class *class, |
| struct class_attribute *attr, |
| const char *buf, size_t size) |
| { |
| unsigned int tag; |
| ssize_t r; |
| |
| r = kstrtouint(buf, 0, &tag); |
| |
| if (r != 0) |
| return -EINVAL; |
| if (tag < KERNEL_ATRACE_TAG_MAX) |
| set_atrace_tag_enabled(tag, !get_atrace_tag_enabled(tag)); |
| |
| return size; |
| } |
| |
| static struct class_attribute debug_attrs[] = { |
| __ATTR(atrace_tag, 0664, show_atrace_tag, store_atrace_tag), |
| __ATTR_NULL |
| }; |
| |
| static struct attribute *debug_class_attrs[] = { |
| &debug_attrs[0].attr, |
| NULL |
| }; |
| |
| ATTRIBUTE_GROUPS(debug_class); |
| |
| static struct class debug_class = { |
| .name = "debug", |
| .class_groups = debug_class_groups, |
| }; |
| |
| int meson_atrace_init(void) |
| { |
| int r; |
| |
| r = class_register(&debug_class); |
| |
| if (r) { |
| pr_err("debug class create fail.\n"); |
| return r; |
| } |
| |
| return 0; |
| } |
| |
| static char *print_flags_type(unsigned int flags) |
| { |
| if (flags & 1UL << KERNEL_ATRACE_COUNTER) |
| return "C"; |
| else if (flags & 1UL << KERNEL_ATRACE_BEGIN) |
| return "B"; |
| else if (flags & 1UL << KERNEL_ATRACE_END) |
| return "E"; |
| else if (flags & 1UL << KERNEL_ATRACE_ASYNC_BEGIN) |
| return "S"; |
| else if (flags & 1UL << KERNEL_ATRACE_ASYNC_END) |
| return "F"; |
| |
| return NULL; |
| } |
| |
| static noinline void tracing_mark_write(char *buf) |
| { |
| __trace_puts(_THIS_IP_, buf, strlen(buf)); |
| } |
| |
| void meson_atrace(int tag, const char *name, unsigned int flags, |
| unsigned long value) |
| { |
| char buf[256]; |
| |
| if (get_atrace_tag_enabled(tag)) { |
| snprintf(buf, sizeof(buf), "%s|1|%s|%lu\n", |
| print_flags_type(flags), name, value); |
| tracing_mark_write(buf); |
| } |
| } |
| EXPORT_SYMBOL(meson_atrace); |
| |
| void __aml_trace_printk(unsigned long ip, const char *fmt, ...) |
| { |
| int len = 0; |
| char buf[1024]; |
| va_list ap; |
| |
| va_start(ap, fmt); |
| len = vscnprintf(buf, sizeof(buf), fmt, ap); |
| if (len > 0) |
| __trace_puts(ip, buf, strlen(buf)); |
| va_end(ap); |
| } |
| EXPORT_SYMBOL(__aml_trace_printk); |