2 * Copyright (C) 2011-2012 ARM Limited. All rights reserved.
4 * This program is free software and is provided to you under the terms of the GNU General Public License version 2
5 * as published by the Free Software Foundation, and any use by you of this program is subject to the terms of such GNU licence.
7 * A copy of the licence is included with the program, and can also be obtained from Free Software
8 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
13 * @file mali_kernel_sysfs.c
14 * Implementation of some sysfs data exports
17 #include <linux/kernel.h>
19 #include <linux/device.h>
20 #include <linux/module.h>
21 #include "mali_kernel_license.h"
22 #include "mali_kernel_common.h"
25 #if MALI_LICENSE_IS_GPL
27 #include <linux/seq_file.h>
28 #include <linux/debugfs.h>
29 #include <asm/uaccess.h>
30 #include <linux/module.h>
31 #include <linux/mali/mali_utgard.h>
32 #include "mali_kernel_sysfs.h"
33 #if defined(CONFIG_MALI400_INTERNAL_PROFILING)
34 #include <linux/slab.h>
35 #include "mali_osk_profiling.h"
38 #include <linux/mali/mali_utgard.h>
41 #include "mali_group.h"
44 #include "mali_l2_cache.h"
45 #include "mali_hw_core.h"
46 #include "mali_kernel_core.h"
47 #include "mali_user_settings_db.h"
48 #include "mali_profiling_internal.h"
49 #include "mali_gp_job.h"
50 #include "mali_pp_job.h"
51 #include "mali_pp_scheduler.h"
53 #define PRIVATE_DATA_COUNTER_MAKE_GP(src) (src)
54 #define PRIVATE_DATA_COUNTER_MAKE_PP(src) ((1 << 24) | src)
55 #define PRIVATE_DATA_COUNTER_MAKE_PP_SUB_JOB(src, sub_job) ((1 << 24) | (1 << 16) | (sub_job << 8) | src)
56 #define PRIVATE_DATA_COUNTER_IS_PP(a) ((((a) >> 24) & 0xFF) ? MALI_TRUE : MALI_FALSE)
57 #define PRIVATE_DATA_COUNTER_GET_SRC(a) (a & 0xFF)
58 #define PRIVATE_DATA_COUNTER_IS_SUB_JOB(a) ((((a) >> 16) & 0xFF) ? MALI_TRUE : MALI_FALSE)
59 #define PRIVATE_DATA_COUNTER_GET_SUB_JOB(a) (((a) >> 8) & 0xFF)
61 #define POWER_BUFFER_SIZE 3
63 static struct dentry *mali_debugfs_dir = NULL;
68 _MALI_DEVICE_DVFS_PAUSE,
69 _MALI_DEVICE_DVFS_RESUME,
71 } _mali_device_debug_power_events;
73 static const char* const mali_power_events[_MALI_MAX_EVENTS] = {
74 [_MALI_DEVICE_SUSPEND] = "suspend",
75 [_MALI_DEVICE_RESUME] = "resume",
76 [_MALI_DEVICE_DVFS_PAUSE] = "dvfs_pause",
77 [_MALI_DEVICE_DVFS_RESUME] = "dvfs_resume",
80 static mali_bool power_always_on_enabled = MALI_FALSE;
82 static int open_copy_private_data(struct inode *inode, struct file *filp)
84 filp->private_data = inode->i_private;
88 static ssize_t group_enabled_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
92 struct mali_group *group;
94 group = (struct mali_group *)filp->private_data;
95 MALI_DEBUG_ASSERT_POINTER(group);
97 r = sprintf(buffer, "%u\n", mali_group_is_enabled(group) ? 1 : 0);
99 return simple_read_from_buffer(buf, count, offp, buffer, r);
102 static ssize_t group_enabled_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
107 struct mali_group *group;
109 group = (struct mali_group *)filp->private_data;
110 MALI_DEBUG_ASSERT_POINTER(group);
112 if (count >= sizeof(buffer)) {
116 if (copy_from_user(&buffer[0], buf, count)) {
119 buffer[count] = '\0';
121 r = strict_strtoul(&buffer[0], 10, &val);
128 mali_group_enable(group);
131 mali_group_disable(group);
142 static const struct file_operations group_enabled_fops = {
143 .owner = THIS_MODULE,
144 .open = open_copy_private_data,
145 .read = group_enabled_read,
146 .write = group_enabled_write,
149 static ssize_t hw_core_base_addr_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
153 struct mali_hw_core *hw_core;
155 hw_core = (struct mali_hw_core *)filp->private_data;
156 MALI_DEBUG_ASSERT_POINTER(hw_core);
158 r = sprintf(buffer, "0x%08X\n", hw_core->phys_addr);
160 return simple_read_from_buffer(buf, count, offp, buffer, r);
163 static const struct file_operations hw_core_base_addr_fops = {
164 .owner = THIS_MODULE,
165 .open = open_copy_private_data,
166 .read = hw_core_base_addr_read,
169 static ssize_t profiling_counter_src_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
171 u32 is_pp = PRIVATE_DATA_COUNTER_IS_PP((u32)filp->private_data);
172 u32 src_id = PRIVATE_DATA_COUNTER_GET_SRC((u32)filp->private_data);
173 mali_bool is_sub_job = PRIVATE_DATA_COUNTER_IS_SUB_JOB((u32)filp->private_data);
174 u32 sub_job = PRIVATE_DATA_COUNTER_GET_SUB_JOB((u32)filp->private_data);
179 if (MALI_TRUE == is_pp) {
181 if (MALI_TRUE == is_sub_job) {
182 /* Get counter for a particular sub job */
184 val = mali_pp_job_get_pp_counter_sub_job_src0(sub_job);
186 val = mali_pp_job_get_pp_counter_sub_job_src1(sub_job);
189 /* Get default counter for all PP sub jobs */
191 val = mali_pp_job_get_pp_counter_global_src0();
193 val = mali_pp_job_get_pp_counter_global_src1();
199 val = mali_gp_job_get_gp_counter_src0();
201 val = mali_gp_job_get_gp_counter_src1();
205 if (MALI_HW_CORE_NO_COUNTER == val) {
206 r = sprintf(buf, "-1\n");
208 r = sprintf(buf, "%u\n", val);
211 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
214 static ssize_t profiling_counter_src_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
216 u32 is_pp = PRIVATE_DATA_COUNTER_IS_PP((u32)filp->private_data);
217 u32 src_id = PRIVATE_DATA_COUNTER_GET_SRC((u32)filp->private_data);
218 mali_bool is_sub_job = PRIVATE_DATA_COUNTER_IS_SUB_JOB((u32)filp->private_data);
219 u32 sub_job = PRIVATE_DATA_COUNTER_GET_SUB_JOB((u32)filp->private_data);
224 if (cnt >= sizeof(buf)) {
228 if (copy_from_user(&buf, ubuf, cnt)) {
234 ret = strict_strtol(buf, 10, &val);
240 /* any negative input will disable counter */
241 val = MALI_HW_CORE_NO_COUNTER;
244 if (MALI_TRUE == is_pp) {
246 if (MALI_TRUE == is_sub_job) {
247 /* Set counter for a particular sub job */
249 mali_pp_job_set_pp_counter_sub_job_src0(sub_job, (u32)val);
251 mali_pp_job_set_pp_counter_sub_job_src1(sub_job, (u32)val);
254 /* Set default counter for all PP sub jobs */
256 mali_pp_job_set_pp_counter_global_src0((u32)val);
258 mali_pp_job_set_pp_counter_global_src1((u32)val);
264 mali_gp_job_set_gp_counter_src0((u32)val);
266 mali_gp_job_set_gp_counter_src1((u32)val);
274 static const struct file_operations profiling_counter_src_fops = {
275 .owner = THIS_MODULE,
276 .open = open_copy_private_data,
277 .read = profiling_counter_src_read,
278 .write = profiling_counter_src_write,
281 static ssize_t l2_l2x_counter_srcx_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id)
286 struct mali_l2_cache_core *l2_core = (struct mali_l2_cache_core *)filp->private_data;
289 val = mali_l2_cache_core_get_counter_src0(l2_core);
291 val = mali_l2_cache_core_get_counter_src1(l2_core);
294 if (MALI_HW_CORE_NO_COUNTER == val) {
295 r = sprintf(buf, "-1\n");
297 r = sprintf(buf, "%u\n", val);
299 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
302 static ssize_t l2_l2x_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id)
304 struct mali_l2_cache_core *l2_core = (struct mali_l2_cache_core *)filp->private_data;
309 if (cnt >= sizeof(buf)) {
313 if (copy_from_user(&buf, ubuf, cnt)) {
319 ret = strict_strtol(buf, 10, &val);
325 /* any negative input will disable counter */
326 val = MALI_HW_CORE_NO_COUNTER;
330 mali_l2_cache_core_set_counter_src0(l2_core, (u32)val);
332 mali_l2_cache_core_set_counter_src1(l2_core, (u32)val);
339 static ssize_t l2_all_counter_srcx_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos, u32 src_id)
345 struct mali_l2_cache_core *l2_cache;
347 if (cnt >= sizeof(buf)) {
351 if (copy_from_user(&buf, ubuf, cnt)) {
357 ret = strict_strtol(buf, 10, &val);
363 /* any negative input will disable counter */
364 val = MALI_HW_CORE_NO_COUNTER;
368 l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id);
369 while (NULL != l2_cache) {
371 mali_l2_cache_core_set_counter_src0(l2_cache, (u32)val);
373 mali_l2_cache_core_set_counter_src1(l2_cache, (u32)val);
378 l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id);
385 static ssize_t l2_l2x_counter_src0_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
387 return l2_l2x_counter_srcx_read(filp, ubuf, cnt, ppos, 0);
390 static ssize_t l2_l2x_counter_src1_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
392 return l2_l2x_counter_srcx_read(filp, ubuf, cnt, ppos, 1);
395 static ssize_t l2_l2x_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
397 return l2_l2x_counter_srcx_write(filp, ubuf, cnt, ppos, 0);
400 static ssize_t l2_l2x_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
402 return l2_l2x_counter_srcx_write(filp, ubuf, cnt, ppos, 1);
405 static ssize_t l2_all_counter_src0_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
407 return l2_all_counter_srcx_write(filp, ubuf, cnt, ppos, 0);
410 static ssize_t l2_all_counter_src1_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
412 return l2_all_counter_srcx_write(filp, ubuf, cnt, ppos, 1);
415 static const struct file_operations l2_l2x_counter_src0_fops = {
416 .owner = THIS_MODULE,
417 .open = open_copy_private_data,
418 .read = l2_l2x_counter_src0_read,
419 .write = l2_l2x_counter_src0_write,
422 static const struct file_operations l2_l2x_counter_src1_fops = {
423 .owner = THIS_MODULE,
424 .open = open_copy_private_data,
425 .read = l2_l2x_counter_src1_read,
426 .write = l2_l2x_counter_src1_write,
429 static const struct file_operations l2_all_counter_src0_fops = {
430 .owner = THIS_MODULE,
431 .write = l2_all_counter_src0_write,
434 static const struct file_operations l2_all_counter_src1_fops = {
435 .owner = THIS_MODULE,
436 .write = l2_all_counter_src1_write,
439 static ssize_t power_always_on_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
445 cnt = min(cnt, sizeof(buf) - 1);
446 if (copy_from_user(buf, ubuf, cnt)) {
451 ret = strict_strtoul(buf, 10, &val);
456 /* Update setting (not exactly thread safe) */
457 if (1 == val && MALI_FALSE == power_always_on_enabled) {
458 power_always_on_enabled = MALI_TRUE;
459 _mali_osk_pm_dev_ref_add();
460 } else if (0 == val && MALI_TRUE == power_always_on_enabled) {
461 power_always_on_enabled = MALI_FALSE;
462 _mali_osk_pm_dev_ref_dec();
469 static ssize_t power_always_on_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
471 if (MALI_TRUE == power_always_on_enabled) {
472 return simple_read_from_buffer(ubuf, cnt, ppos, "1\n", 2);
474 return simple_read_from_buffer(ubuf, cnt, ppos, "0\n", 2);
478 static const struct file_operations power_always_on_fops = {
479 .owner = THIS_MODULE,
480 .read = power_always_on_read,
481 .write = power_always_on_write,
484 static ssize_t power_power_events_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
487 if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_SUSPEND],strlen(mali_power_events[_MALI_DEVICE_SUSPEND]))) {
488 mali_pm_os_suspend();
490 } else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_RESUME],strlen(mali_power_events[_MALI_DEVICE_RESUME]))) {
492 } else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_DVFS_PAUSE],strlen(mali_power_events[_MALI_DEVICE_DVFS_PAUSE]))) {
494 } else if (!strncmp(ubuf,mali_power_events[_MALI_DEVICE_DVFS_RESUME],strlen(mali_power_events[_MALI_DEVICE_DVFS_RESUME]))) {
501 static loff_t power_power_events_seek(struct file *file, loff_t offset, int orig)
503 file->f_pos = offset;
507 static const struct file_operations power_power_events_fops = {
508 .owner = THIS_MODULE,
509 .write = power_power_events_write,
510 .llseek = power_power_events_seek,
513 #if MALI_STATE_TRACKING
514 static int mali_seq_internal_state_show(struct seq_file *seq_file, void *v)
520 size = seq_get_buf(seq_file, &buf);
526 /* Create the internal state dump. */
527 len = snprintf(buf+len, size-len, "Mali device driver %s\n", SVN_REV_STRING);
528 len += snprintf(buf+len, size-len, "License: %s\n\n", MALI_KERNEL_LINUX_LICENSE);
530 len += _mali_kernel_core_dump_state(buf + len, size - len);
532 seq_commit(seq_file, len);
537 static int mali_seq_internal_state_open(struct inode *inode, struct file *file)
539 return single_open(file, mali_seq_internal_state_show, NULL);
542 static const struct file_operations mali_seq_internal_state_fops = {
543 .owner = THIS_MODULE,
544 .open = mali_seq_internal_state_open,
547 .release = single_release,
549 #endif /* MALI_STATE_TRACKING */
551 #if defined(CONFIG_MALI400_INTERNAL_PROFILING)
552 static ssize_t profiling_record_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
557 r = sprintf(buf, "%u\n", _mali_internal_profiling_is_recording() ? 1 : 0);
558 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
561 static ssize_t profiling_record_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
567 if (cnt >= sizeof(buf)) {
571 if (copy_from_user(&buf, ubuf, cnt)) {
577 ret = strict_strtoul(buf, 10, &val);
583 u32 limit = MALI_PROFILING_MAX_BUFFER_ENTRIES; /* This can be made configurable at a later stage if we need to */
585 /* check if we are already recording */
586 if (MALI_TRUE == _mali_internal_profiling_is_recording()) {
587 MALI_DEBUG_PRINT(3, ("Recording of profiling events already in progress\n"));
591 /* check if we need to clear out an old recording first */
592 if (MALI_TRUE == _mali_internal_profiling_have_recording()) {
593 if (_MALI_OSK_ERR_OK != _mali_internal_profiling_clear()) {
594 MALI_DEBUG_PRINT(3, ("Failed to clear existing recording of profiling events\n"));
599 /* start recording profiling data */
600 if (_MALI_OSK_ERR_OK != _mali_internal_profiling_start(&limit)) {
601 MALI_DEBUG_PRINT(3, ("Failed to start recording of profiling events\n"));
605 MALI_DEBUG_PRINT(3, ("Profiling recording started (max %u events)\n", limit));
607 /* stop recording profiling data */
609 if (_MALI_OSK_ERR_OK != _mali_internal_profiling_stop(&count)) {
610 MALI_DEBUG_PRINT(2, ("Failed to stop recording of profiling events\n"));
614 MALI_DEBUG_PRINT(2, ("Profiling recording stopped (recorded %u events)\n", count));
621 static const struct file_operations profiling_record_fops = {
622 .owner = THIS_MODULE,
623 .read = profiling_record_read,
624 .write = profiling_record_write,
627 static void *profiling_events_start(struct seq_file *s, loff_t *pos)
631 /* check if we have data avaiable */
632 if (MALI_TRUE != _mali_internal_profiling_have_recording()) {
636 spos = kmalloc(sizeof(loff_t), GFP_KERNEL);
645 static void *profiling_events_next(struct seq_file *s, void *v, loff_t *pos)
649 /* check if we have data avaiable */
650 if (MALI_TRUE != _mali_internal_profiling_have_recording()) {
654 /* check if the next entry actually is avaiable */
655 if (_mali_internal_profiling_get_count() <= (u32)(*spos + 1)) {
663 static void profiling_events_stop(struct seq_file *s, void *v)
668 static int profiling_events_show(struct seq_file *seq_file, void *v)
678 /* Retrieve all events */
679 if (_MALI_OSK_ERR_OK == _mali_internal_profiling_get_event(index, ×tamp, &event_id, data)) {
680 seq_printf(seq_file, "%llu %u %u %u %u %u %u\n", timestamp, event_id, data[0], data[1], data[2], data[3], data[4]);
687 static int profiling_events_show_human_readable(struct seq_file *seq_file, void *v)
689 #define MALI_EVENT_ID_IS_HW(event_id) (((event_id & 0x00FF0000) >= MALI_PROFILING_EVENT_CHANNEL_GP0) && ((event_id & 0x00FF0000) <= MALI_PROFILING_EVENT_CHANNEL_PP7))
691 static u64 start_time = 0;
700 /* Retrieve all events */
701 if (_MALI_OSK_ERR_OK == _mali_internal_profiling_get_event(index, ×tamp, &event_id, data)) {
702 seq_printf(seq_file, "%llu %u %u %u %u %u %u # ", timestamp, event_id, data[0], data[1], data[2], data[3], data[4]);
705 start_time = timestamp;
708 seq_printf(seq_file, "[%06u] ", index);
710 switch(event_id & 0x0F000000) {
711 case MALI_PROFILING_EVENT_TYPE_SINGLE:
712 seq_printf(seq_file, "SINGLE | ");
714 case MALI_PROFILING_EVENT_TYPE_START:
715 seq_printf(seq_file, "START | ");
717 case MALI_PROFILING_EVENT_TYPE_STOP:
718 seq_printf(seq_file, "STOP | ");
720 case MALI_PROFILING_EVENT_TYPE_SUSPEND:
721 seq_printf(seq_file, "SUSPEND | ");
723 case MALI_PROFILING_EVENT_TYPE_RESUME:
724 seq_printf(seq_file, "RESUME | ");
727 seq_printf(seq_file, "0x%01X | ", (event_id & 0x0F000000) >> 24);
731 switch(event_id & 0x00FF0000) {
732 case MALI_PROFILING_EVENT_CHANNEL_SOFTWARE:
733 seq_printf(seq_file, "SW | ");
735 case MALI_PROFILING_EVENT_CHANNEL_GP0:
736 seq_printf(seq_file, "GP0 | ");
738 case MALI_PROFILING_EVENT_CHANNEL_PP0:
739 seq_printf(seq_file, "PP0 | ");
741 case MALI_PROFILING_EVENT_CHANNEL_PP1:
742 seq_printf(seq_file, "PP1 | ");
744 case MALI_PROFILING_EVENT_CHANNEL_PP2:
745 seq_printf(seq_file, "PP2 | ");
747 case MALI_PROFILING_EVENT_CHANNEL_PP3:
748 seq_printf(seq_file, "PP3 | ");
750 case MALI_PROFILING_EVENT_CHANNEL_PP4:
751 seq_printf(seq_file, "PP4 | ");
753 case MALI_PROFILING_EVENT_CHANNEL_PP5:
754 seq_printf(seq_file, "PP5 | ");
756 case MALI_PROFILING_EVENT_CHANNEL_PP6:
757 seq_printf(seq_file, "PP6 | ");
759 case MALI_PROFILING_EVENT_CHANNEL_PP7:
760 seq_printf(seq_file, "PP7 | ");
762 case MALI_PROFILING_EVENT_CHANNEL_GPU:
763 seq_printf(seq_file, "GPU | ");
766 seq_printf(seq_file, "0x%02X | ", (event_id & 0x00FF0000) >> 16);
770 if (MALI_EVENT_ID_IS_HW(event_id)) {
771 if (((event_id & 0x0F000000) == MALI_PROFILING_EVENT_TYPE_START) || ((event_id & 0x0F000000) == MALI_PROFILING_EVENT_TYPE_STOP)) {
772 switch(event_id & 0x0000FFFF) {
773 case MALI_PROFILING_EVENT_REASON_START_STOP_HW_PHYSICAL:
774 seq_printf(seq_file, "PHYSICAL | ");
776 case MALI_PROFILING_EVENT_REASON_START_STOP_HW_VIRTUAL:
777 seq_printf(seq_file, "VIRTUAL | ");
780 seq_printf(seq_file, "0x%04X | ", event_id & 0x0000FFFF);
784 seq_printf(seq_file, "0x%04X | ", event_id & 0x0000FFFF);
787 seq_printf(seq_file, "0x%04X | ", event_id & 0x0000FFFF);
790 seq_printf(seq_file, "T0 + 0x%016llX\n", timestamp - start_time);
798 static const struct seq_operations profiling_events_seq_ops = {
799 .start = profiling_events_start,
800 .next = profiling_events_next,
801 .stop = profiling_events_stop,
802 .show = profiling_events_show
805 static int profiling_events_open(struct inode *inode, struct file *file)
807 return seq_open(file, &profiling_events_seq_ops);
810 static const struct file_operations profiling_events_fops = {
811 .owner = THIS_MODULE,
812 .open = profiling_events_open,
815 .release = seq_release,
818 static const struct seq_operations profiling_events_human_readable_seq_ops = {
819 .start = profiling_events_start,
820 .next = profiling_events_next,
821 .stop = profiling_events_stop,
822 .show = profiling_events_show_human_readable
825 static int profiling_events_human_readable_open(struct inode *inode, struct file *file)
827 return seq_open(file, &profiling_events_human_readable_seq_ops);
830 static const struct file_operations profiling_events_human_readable_fops = {
831 .owner = THIS_MODULE,
832 .open = profiling_events_human_readable_open,
835 .release = seq_release,
840 static ssize_t memory_used_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
844 u32 mem = _mali_ukk_report_memory_usage();
846 r = snprintf(buf, 64, "%u\n", mem);
847 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
850 static const struct file_operations memory_usage_fops = {
851 .owner = THIS_MODULE,
852 .read = memory_used_read,
855 static ssize_t utilization_gp_pp_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
859 u32 uval= _mali_ukk_utilization_gp_pp();
861 r = snprintf(buf, 64, "%u\n", uval);
862 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
865 static ssize_t utilization_gp_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
869 u32 uval= _mali_ukk_utilization_gp();
871 r = snprintf(buf, 64, "%u\n", uval);
872 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
875 static ssize_t utilization_pp_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
879 u32 uval= _mali_ukk_utilization_pp();
881 r = snprintf(buf, 64, "%u\n", uval);
882 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
886 static const struct file_operations utilization_gp_pp_fops = {
887 .owner = THIS_MODULE,
888 .read = utilization_gp_pp_read,
891 static const struct file_operations utilization_gp_fops = {
892 .owner = THIS_MODULE,
893 .read = utilization_gp_read,
896 static const struct file_operations utilization_pp_fops = {
897 .owner = THIS_MODULE,
898 .read = utilization_pp_read,
901 static ssize_t user_settings_write(struct file *filp, const char __user *ubuf, size_t cnt, loff_t *ppos)
905 _mali_uk_user_setting_t setting;
908 cnt = min(cnt, sizeof(buf) - 1);
909 if (copy_from_user(buf, ubuf, cnt)) {
914 ret = strict_strtoul(buf, 10, &val);
920 setting = (_mali_uk_user_setting_t)(filp->private_data);
921 mali_set_user_setting(setting, val);
927 static ssize_t user_settings_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
932 _mali_uk_user_setting_t setting;
934 setting = (_mali_uk_user_setting_t)(filp->private_data);
935 value = mali_get_user_setting(setting);
937 r = snprintf(buf, 64, "%u\n", value);
938 return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
941 static const struct file_operations user_settings_fops = {
942 .owner = THIS_MODULE,
943 .open = open_copy_private_data,
944 .read = user_settings_read,
945 .write = user_settings_write,
948 static int mali_sysfs_user_settings_register(void)
950 struct dentry *mali_user_settings_dir = debugfs_create_dir("userspace_settings", mali_debugfs_dir);
952 if (mali_user_settings_dir != NULL) {
954 for (i = 0; i < _MALI_UK_USER_SETTING_MAX; i++) {
955 debugfs_create_file(_mali_uk_user_setting_descriptions[i], 0600, mali_user_settings_dir, (void*)i, &user_settings_fops);
962 static ssize_t pmu_power_down_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
967 struct mali_pmu_core *pmu;
968 _mali_osk_errcode_t err;
970 if (count >= sizeof(buffer)) {
974 if (copy_from_user(&buffer[0], buf, count)) {
977 buffer[count] = '\0';
979 ret = strict_strtoul(&buffer[0], 10, &val);
984 pmu = mali_pmu_get_global_pmu_core();
985 MALI_DEBUG_ASSERT_POINTER(pmu);
987 err = mali_pmu_power_down(pmu, val);
988 if (_MALI_OSK_ERR_OK != err) {
996 static ssize_t pmu_power_up_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
1001 struct mali_pmu_core *pmu;
1002 _mali_osk_errcode_t err;
1004 if (count >= sizeof(buffer)) {
1008 if (copy_from_user(&buffer[0], buf, count)) {
1011 buffer[count] = '\0';
1013 ret = strict_strtoul(&buffer[0], 10, &val);
1018 pmu = mali_pmu_get_global_pmu_core();
1019 MALI_DEBUG_ASSERT_POINTER(pmu);
1021 err = mali_pmu_power_up(pmu, val);
1022 if (_MALI_OSK_ERR_OK != err) {
1030 static const struct file_operations pmu_power_down_fops = {
1031 .owner = THIS_MODULE,
1032 .write = pmu_power_down_write,
1035 static const struct file_operations pmu_power_up_fops = {
1036 .owner = THIS_MODULE,
1037 .write = pmu_power_up_write,
1040 static ssize_t pp_num_cores_enabled_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
1046 if (count >= sizeof(buffer)) {
1050 if (copy_from_user(&buffer[0], buf, count)) {
1053 buffer[count] = '\0';
1055 ret = strict_strtoul(&buffer[0], 10, &val);
1060 ret = mali_pp_scheduler_set_perf_level(val, MALI_TRUE); /* override even if core scaling is disabled */
1069 static ssize_t pp_num_cores_enabled_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
1074 r = sprintf(buffer, "%u\n", mali_pp_scheduler_get_num_cores_enabled());
1076 return simple_read_from_buffer(buf, count, offp, buffer, r);
1079 static const struct file_operations pp_num_cores_enabled_fops = {
1080 .owner = THIS_MODULE,
1081 .write = pp_num_cores_enabled_write,
1082 .read = pp_num_cores_enabled_read,
1083 .llseek = default_llseek,
1086 static ssize_t pp_num_cores_total_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
1091 r = sprintf(buffer, "%u\n", mali_pp_scheduler_get_num_cores_total());
1093 return simple_read_from_buffer(buf, count, offp, buffer, r);
1096 static const struct file_operations pp_num_cores_total_fops = {
1097 .owner = THIS_MODULE,
1098 .read = pp_num_cores_total_read,
1101 static ssize_t pp_core_scaling_enabled_write(struct file *filp, const char __user *buf, size_t count, loff_t *offp)
1107 if (count >= sizeof(buffer)) {
1111 if (copy_from_user(&buffer[0], buf, count)) {
1114 buffer[count] = '\0';
1116 ret = strict_strtoul(&buffer[0], 10, &val);
1123 mali_pp_scheduler_core_scaling_enable();
1126 mali_pp_scheduler_core_scaling_disable();
1137 static ssize_t pp_core_scaling_enabled_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
1139 return simple_read_from_buffer(buf, count, offp, mali_pp_scheduler_core_scaling_is_enabled() ? "1\n" : "0\n", 2);
1141 static const struct file_operations pp_core_scaling_enabled_fops = {
1142 .owner = THIS_MODULE,
1143 .write = pp_core_scaling_enabled_write,
1144 .read = pp_core_scaling_enabled_read,
1145 .llseek = default_llseek,
1148 static ssize_t version_read(struct file *filp, char __user *buf, size_t count, loff_t *offp)
1153 switch (mali_kernel_core_get_product_id()) {
1154 case _MALI_PRODUCT_ID_MALI200:
1155 r = sprintf(buffer, "Mali-200\n");
1157 case _MALI_PRODUCT_ID_MALI300:
1158 r = sprintf(buffer, "Mali-300\n");
1160 case _MALI_PRODUCT_ID_MALI400:
1161 r = sprintf(buffer, "Mali-400 MP\n");
1163 case _MALI_PRODUCT_ID_MALI450:
1164 r = sprintf(buffer, "Mali-450 MP\n");
1166 case _MALI_PRODUCT_ID_UNKNOWN:
1171 return simple_read_from_buffer(buf, count, offp, buffer, r);
1174 static const struct file_operations version_fops = {
1175 .owner = THIS_MODULE,
1176 .read = version_read,
1179 int mali_sysfs_register(const char *mali_dev_name)
1181 mali_debugfs_dir = debugfs_create_dir(mali_dev_name, NULL);
1182 if(ERR_PTR(-ENODEV) == mali_debugfs_dir) {
1183 /* Debugfs not supported. */
1184 mali_debugfs_dir = NULL;
1186 if(NULL != mali_debugfs_dir) {
1187 /* Debugfs directory created successfully; create files now */
1188 struct dentry *mali_pmu_dir;
1189 struct dentry *mali_power_dir;
1190 struct dentry *mali_gp_dir;
1191 struct dentry *mali_pp_dir;
1192 struct dentry *mali_l2_dir;
1193 struct dentry *mali_profiling_dir;
1195 debugfs_create_file("version", 0400, mali_debugfs_dir, NULL, &version_fops);
1197 mali_pmu_dir = debugfs_create_dir("pmu", mali_debugfs_dir);
1198 if (NULL != mali_pmu_dir) {
1199 debugfs_create_file("power_down", 0200, mali_pmu_dir, NULL, &pmu_power_down_fops);
1200 debugfs_create_file("power_up", 0200, mali_pmu_dir, NULL, &pmu_power_up_fops);
1203 mali_power_dir = debugfs_create_dir("power", mali_debugfs_dir);
1204 if (mali_power_dir != NULL) {
1205 /* MALI_SEC : 0600 -> 0400 */
1206 debugfs_create_file("always_on", 0400, mali_power_dir, NULL, &power_always_on_fops);
1207 /* MALI_SEC : 0200 -> 0400 */
1208 debugfs_create_file("power_events", 0400, mali_power_dir, NULL, &power_power_events_fops);
1211 mali_gp_dir = debugfs_create_dir("gp", mali_debugfs_dir);
1212 if (mali_gp_dir != NULL) {
1216 num_groups = mali_group_get_glob_num_groups();
1217 for (i = 0; i < num_groups; i++) {
1218 struct mali_group *group = mali_group_get_glob_group(i);
1220 struct mali_gp_core *gp_core = mali_group_get_gp_core(group);
1221 if (NULL != gp_core) {
1222 struct dentry *mali_gp_gpx_dir;
1223 mali_gp_gpx_dir = debugfs_create_dir("gp0", mali_gp_dir);
1224 if (NULL != mali_gp_gpx_dir) {
1225 debugfs_create_file("base_addr", 0400, mali_gp_gpx_dir, &gp_core->hw_core, &hw_core_base_addr_fops);
1226 debugfs_create_file("enabled", 0600, mali_gp_gpx_dir, group, &group_enabled_fops);
1228 break; /* no need to look for any other GP cores */
1234 mali_pp_dir = debugfs_create_dir("pp", mali_debugfs_dir);
1235 if (mali_pp_dir != NULL) {
1239 debugfs_create_file("num_cores_total", 0400, mali_pp_dir, NULL, &pp_num_cores_total_fops);
1240 debugfs_create_file("num_cores_enabled", 0600, mali_pp_dir, NULL, &pp_num_cores_enabled_fops);
1241 debugfs_create_file("core_scaling_enabled", 0600, mali_pp_dir, NULL, &pp_core_scaling_enabled_fops);
1243 num_groups = mali_group_get_glob_num_groups();
1244 for (i = 0; i < num_groups; i++) {
1245 struct mali_group *group = mali_group_get_glob_group(i);
1247 struct mali_pp_core *pp_core = mali_group_get_pp_core(group);
1248 if (NULL != pp_core) {
1250 struct dentry *mali_pp_ppx_dir;
1251 _mali_osk_snprintf(buf, sizeof(buf), "pp%u", mali_pp_core_get_id(pp_core));
1252 mali_pp_ppx_dir = debugfs_create_dir(buf, mali_pp_dir);
1253 if (NULL != mali_pp_ppx_dir) {
1254 debugfs_create_file("base_addr", 0400, mali_pp_ppx_dir, &pp_core->hw_core, &hw_core_base_addr_fops);
1255 if (!mali_group_is_virtual(group)) {
1256 debugfs_create_file("enabled", 0600, mali_pp_ppx_dir, group, &group_enabled_fops);
1263 mali_l2_dir = debugfs_create_dir("l2", mali_debugfs_dir);
1264 if (mali_l2_dir != NULL) {
1265 struct dentry *mali_l2_all_dir;
1267 struct mali_l2_cache_core *l2_cache;
1269 mali_l2_all_dir = debugfs_create_dir("all", mali_l2_dir);
1270 if (mali_l2_all_dir != NULL) {
1271 debugfs_create_file("counter_src0", 0200, mali_l2_all_dir, NULL, &l2_all_counter_src0_fops);
1272 debugfs_create_file("counter_src1", 0200, mali_l2_all_dir, NULL, &l2_all_counter_src1_fops);
1276 l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id);
1277 while (NULL != l2_cache) {
1279 struct dentry *mali_l2_l2x_dir;
1280 _mali_osk_snprintf(buf, sizeof(buf), "l2%u", l2_id);
1281 mali_l2_l2x_dir = debugfs_create_dir(buf, mali_l2_dir);
1282 if (NULL != mali_l2_l2x_dir) {
1283 debugfs_create_file("counter_src0", 0600, mali_l2_l2x_dir, l2_cache, &l2_l2x_counter_src0_fops);
1284 debugfs_create_file("counter_src1", 0600, mali_l2_l2x_dir, l2_cache, &l2_l2x_counter_src1_fops);
1285 debugfs_create_file("base_addr", 0400, mali_l2_l2x_dir, &l2_cache->hw_core, &hw_core_base_addr_fops);
1290 l2_cache = mali_l2_cache_core_get_glob_l2_core(l2_id);
1294 debugfs_create_file("memory_usage", 0400, mali_debugfs_dir, NULL, &memory_usage_fops);
1296 debugfs_create_file("utilization_gp_pp", 0400, mali_debugfs_dir, NULL, &utilization_gp_pp_fops);
1297 debugfs_create_file("utilization_gp", 0400, mali_debugfs_dir, NULL, &utilization_gp_fops);
1298 debugfs_create_file("utilization_pp", 0400, mali_debugfs_dir, NULL, &utilization_pp_fops);
1300 mali_profiling_dir = debugfs_create_dir("profiling", mali_debugfs_dir);
1301 if (mali_profiling_dir != NULL) {
1304 struct dentry *mali_profiling_gp_dir;
1305 struct dentry *mali_profiling_pp_dir;
1306 #if defined(CONFIG_MALI400_INTERNAL_PROFILING)
1307 struct dentry *mali_profiling_proc_dir;
1310 * Create directory where we can set GP HW counters.
1312 mali_profiling_gp_dir = debugfs_create_dir("gp", mali_profiling_dir);
1313 if (mali_profiling_gp_dir != NULL) {
1314 debugfs_create_file("counter_src0", 0600, mali_profiling_gp_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_GP(0), &profiling_counter_src_fops);
1315 debugfs_create_file("counter_src1", 0600, mali_profiling_gp_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_GP(1), &profiling_counter_src_fops);
1319 * Create directory where we can set PP HW counters.
1320 * Possible override with specific HW counters for a particular sub job
1321 * (Disable core scaling before using the override!)
1323 mali_profiling_pp_dir = debugfs_create_dir("pp", mali_profiling_dir);
1324 if (mali_profiling_pp_dir != NULL) {
1325 debugfs_create_file("counter_src0", 0600, mali_profiling_pp_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_PP(0), &profiling_counter_src_fops);
1326 debugfs_create_file("counter_src1", 0600, mali_profiling_pp_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_PP(1), &profiling_counter_src_fops);
1329 max_sub_jobs = mali_pp_scheduler_get_num_cores_total();
1330 for (i = 0; i < max_sub_jobs; i++) {
1332 struct dentry *mali_profiling_pp_x_dir;
1333 _mali_osk_snprintf(buf, sizeof(buf), "%u", i);
1334 mali_profiling_pp_x_dir = debugfs_create_dir(buf, mali_profiling_pp_dir);
1335 if (NULL != mali_profiling_pp_x_dir) {
1336 debugfs_create_file("counter_src0", 0600, mali_profiling_pp_x_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_PP_SUB_JOB(0, i), &profiling_counter_src_fops);
1337 debugfs_create_file("counter_src1", 0600, mali_profiling_pp_x_dir, (void*)PRIVATE_DATA_COUNTER_MAKE_PP_SUB_JOB(1, i), &profiling_counter_src_fops);
1341 #if defined(CONFIG_MALI400_INTERNAL_PROFILING)
1342 mali_profiling_proc_dir = debugfs_create_dir("proc", mali_profiling_dir);
1343 if (mali_profiling_proc_dir != NULL) {
1344 struct dentry *mali_profiling_proc_default_dir = debugfs_create_dir("default", mali_profiling_proc_dir);
1345 if (mali_profiling_proc_default_dir != NULL) {
1346 debugfs_create_file("enable", 0600, mali_profiling_proc_default_dir, (void*)_MALI_UK_USER_SETTING_SW_EVENTS_ENABLE, &user_settings_fops);
1349 debugfs_create_file("record", 0600, mali_profiling_dir, NULL, &profiling_record_fops);
1350 debugfs_create_file("events", 0400, mali_profiling_dir, NULL, &profiling_events_fops);
1351 debugfs_create_file("events_human_readable", 0400, mali_profiling_dir, NULL, &profiling_events_human_readable_fops);
1355 #if MALI_STATE_TRACKING
1356 debugfs_create_file("state_dump", 0400, mali_debugfs_dir, NULL, &mali_seq_internal_state_fops);
1359 if (mali_sysfs_user_settings_register()) {
1360 /* Failed to create the debugfs entries for the user settings DB. */
1361 MALI_DEBUG_PRINT(2, ("Failed to create user setting debugfs files. Ignoring...\n"));
1370 int mali_sysfs_unregister(void)
1372 if(NULL != mali_debugfs_dir) {
1373 debugfs_remove_recursive(mali_debugfs_dir);
1378 #else /* MALI_LICENSE_IS_GPL */
1380 /* Dummy implementations for non-GPL */
1382 int mali_sysfs_register(struct mali_dev *device, dev_t dev, const char *mali_dev_name)
1387 int mali_sysfs_unregister(void)
1392 #endif /* MALI_LICENSE_IS_GPL */