2c24742eb4de4baeaecbf7fda1c85aefde09f728
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / arm / mali400 / mali / platform / arm / arm_core_scaling.c
1 /*
2  * Copyright (C) 2013-2015 ARM Limited. All rights reserved.
3  * 
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.
6  * 
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.
9  */
10
11 /**
12  * @file arm_core_scaling.c
13  * Example core scaling policy.
14  */
15
16 #include "arm_core_scaling.h"
17
18 #include <linux/mali/mali_utgard.h>
19 #include "mali_kernel_common.h"
20
21 #include <linux/workqueue.h>
22
23 static int num_cores_total;
24 static int num_cores_enabled;
25
26 static struct work_struct wq_work;
27
28 static void set_num_cores(struct work_struct *work)
29 {
30         int err = mali_perf_set_num_pp_cores(num_cores_enabled);
31         MALI_DEBUG_ASSERT(0 == err);
32         MALI_IGNORE(err);
33 }
34
35 static void enable_one_core(void)
36 {
37         if (num_cores_enabled < num_cores_total) {
38                 ++num_cores_enabled;
39                 schedule_work(&wq_work);
40                 MALI_DEBUG_PRINT(3, ("Core scaling: Enabling one more core\n"));
41         }
42
43         MALI_DEBUG_ASSERT(1 <= num_cores_enabled);
44         MALI_DEBUG_ASSERT(num_cores_total >= num_cores_enabled);
45 }
46
47 static void disable_one_core(void)
48 {
49         if (1 < num_cores_enabled) {
50                 --num_cores_enabled;
51                 schedule_work(&wq_work);
52                 MALI_DEBUG_PRINT(3, ("Core scaling: Disabling one core\n"));
53         }
54
55         MALI_DEBUG_ASSERT(1 <= num_cores_enabled);
56         MALI_DEBUG_ASSERT(num_cores_total >= num_cores_enabled);
57 }
58
59 static void enable_max_num_cores(void)
60 {
61         if (num_cores_enabled < num_cores_total) {
62                 num_cores_enabled = num_cores_total;
63                 schedule_work(&wq_work);
64                 MALI_DEBUG_PRINT(3, ("Core scaling: Enabling maximum number of cores\n"));
65         }
66
67         MALI_DEBUG_ASSERT(num_cores_total == num_cores_enabled);
68 }
69
70 void mali_core_scaling_init(int num_pp_cores)
71 {
72         INIT_WORK(&wq_work, set_num_cores);
73
74         num_cores_total   = num_pp_cores;
75         num_cores_enabled = num_pp_cores;
76
77         /* NOTE: Mali is not fully initialized at this point. */
78 }
79
80 void mali_core_scaling_sync(int num_cores)
81 {
82         num_cores_enabled = num_cores;
83 }
84
85 void mali_core_scaling_term(void)
86 {
87         flush_scheduled_work();
88 }
89
90 #define PERCENT_OF(percent, max) ((int) ((percent)*(max)/100.0 + 0.5))
91
92 void mali_core_scaling_update(struct mali_gpu_utilization_data *data)
93 {
94         /*
95          * This function implements a very trivial PP core scaling algorithm.
96          *
97          * It is _NOT_ of production quality.
98          * The only intention behind this algorithm is to exercise and test the
99          * core scaling functionality of the driver.
100          * It is _NOT_ tuned for neither power saving nor performance!
101          *
102          * Other metrics than PP utilization need to be considered as well
103          * in order to make a good core scaling algorithm.
104          */
105
106         MALI_DEBUG_PRINT(3, ("Utilization: (%3d, %3d, %3d), cores enabled: %d/%d\n", data->utilization_gpu, data->utilization_gp, data->utilization_pp, num_cores_enabled, num_cores_total));
107
108         /* NOTE: this function is normally called directly from the utilization callback which is in
109          * timer context. */
110
111         if (PERCENT_OF(90, 256) < data->utilization_pp) {
112                 enable_max_num_cores();
113         } else if (PERCENT_OF(50, 256) < data->utilization_pp) {
114                 enable_one_core();
115         } else if (PERCENT_OF(40, 256) < data->utilization_pp) {
116                 /* do nothing */
117         } else if (PERCENT_OF(0, 256) < data->utilization_pp) {
118                 disable_one_core();
119         } else {
120                 /* do nothing */
121         }
122 }