Commit | Line | Data |
---|---|---|
d25bc64b JY |
1 | /* |
2 | * | |
142b0cea | 3 | * (C) COPYRIGHT 2013-2017 ARM Limited. All rights reserved. |
d25bc64b JY |
4 | * |
5 | * This program is free software and is provided to you under the terms of the | |
6 | * GNU General Public License version 2 as published by the Free Software | |
7 | * Foundation, and any use by you of this program is subject to the terms | |
8 | * of such GNU licence. | |
9 | * | |
10 | * A copy of the licence is included with the program, and can also be obtained | |
11 | * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
12 | * Boston, MA 02110-1301, USA. | |
13 | * | |
14 | */ | |
15 | ||
16 | ||
17 | ||
18 | /* | |
19 | * Base kernel core availability APIs | |
20 | */ | |
21 | ||
22 | #include <mali_kbase.h> | |
23 | #include <mali_kbase_pm.h> | |
24 | #include <backend/gpu/mali_kbase_pm_internal.h> | |
25 | ||
26 | static const struct kbase_pm_ca_policy *const policy_list[] = { | |
27 | &kbase_pm_ca_fixed_policy_ops, | |
142b0cea | 28 | #ifdef CONFIG_MALI_DEVFREQ |
29 | &kbase_pm_ca_devfreq_policy_ops, | |
30 | #endif | |
d25bc64b | 31 | #if !MALI_CUSTOMER_RELEASE |
1b7e57c0 JY |
32 | &kbase_pm_ca_demand_policy_ops, |
33 | &kbase_pm_ca_random_policy_ops, | |
d25bc64b JY |
34 | #endif |
35 | }; | |
36 | ||
37 | /** | |
38 | * POLICY_COUNT - The number of policies available in the system. | |
39 | * | |
40 | * This is derived from the number of functions listed in policy_list. | |
41 | */ | |
42 | #define POLICY_COUNT (sizeof(policy_list)/sizeof(*policy_list)) | |
43 | ||
44 | int kbase_pm_ca_init(struct kbase_device *kbdev) | |
45 | { | |
46 | KBASE_DEBUG_ASSERT(kbdev != NULL); | |
47 | ||
48 | kbdev->pm.backend.ca_current_policy = policy_list[0]; | |
49 | ||
50 | kbdev->pm.backend.ca_current_policy->init(kbdev); | |
51 | ||
52 | return 0; | |
53 | } | |
54 | ||
55 | void kbase_pm_ca_term(struct kbase_device *kbdev) | |
56 | { | |
57 | kbdev->pm.backend.ca_current_policy->term(kbdev); | |
58 | } | |
59 | ||
60 | int kbase_pm_ca_list_policies(const struct kbase_pm_ca_policy * const **list) | |
61 | { | |
62 | if (!list) | |
63 | return POLICY_COUNT; | |
64 | ||
65 | *list = policy_list; | |
66 | ||
67 | return POLICY_COUNT; | |
68 | } | |
69 | ||
70 | KBASE_EXPORT_TEST_API(kbase_pm_ca_list_policies); | |
71 | ||
72 | const struct kbase_pm_ca_policy | |
73 | *kbase_pm_ca_get_policy(struct kbase_device *kbdev) | |
74 | { | |
75 | KBASE_DEBUG_ASSERT(kbdev != NULL); | |
76 | ||
77 | return kbdev->pm.backend.ca_current_policy; | |
78 | } | |
79 | ||
80 | KBASE_EXPORT_TEST_API(kbase_pm_ca_get_policy); | |
81 | ||
82 | void kbase_pm_ca_set_policy(struct kbase_device *kbdev, | |
83 | const struct kbase_pm_ca_policy *new_policy) | |
84 | { | |
85 | const struct kbase_pm_ca_policy *old_policy; | |
86 | unsigned long flags; | |
87 | ||
88 | KBASE_DEBUG_ASSERT(kbdev != NULL); | |
89 | KBASE_DEBUG_ASSERT(new_policy != NULL); | |
90 | ||
91 | KBASE_TRACE_ADD(kbdev, PM_CA_SET_POLICY, NULL, NULL, 0u, | |
92 | new_policy->id); | |
93 | ||
94 | /* During a policy change we pretend the GPU is active */ | |
95 | /* A suspend won't happen here, because we're in a syscall from a | |
96 | * userspace thread */ | |
97 | kbase_pm_context_active(kbdev); | |
98 | ||
99 | mutex_lock(&kbdev->pm.lock); | |
100 | ||
101 | /* Remove the policy to prevent IRQ handlers from working on it */ | |
dd8e48ad | 102 | spin_lock_irqsave(&kbdev->hwaccess_lock, flags); |
d25bc64b JY |
103 | old_policy = kbdev->pm.backend.ca_current_policy; |
104 | kbdev->pm.backend.ca_current_policy = NULL; | |
dd8e48ad | 105 | spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); |
d25bc64b JY |
106 | |
107 | if (old_policy->term) | |
108 | old_policy->term(kbdev); | |
109 | ||
110 | if (new_policy->init) | |
111 | new_policy->init(kbdev); | |
112 | ||
dd8e48ad | 113 | spin_lock_irqsave(&kbdev->hwaccess_lock, flags); |
d25bc64b JY |
114 | kbdev->pm.backend.ca_current_policy = new_policy; |
115 | ||
116 | /* If any core power state changes were previously attempted, but | |
117 | * couldn't be made because the policy was changing (current_policy was | |
118 | * NULL), then re-try them here. */ | |
119 | kbase_pm_update_cores_state_nolock(kbdev); | |
120 | ||
121 | kbdev->pm.backend.ca_current_policy->update_core_status(kbdev, | |
122 | kbdev->shader_ready_bitmap, | |
123 | kbdev->shader_transitioning_bitmap); | |
124 | ||
dd8e48ad | 125 | spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); |
d25bc64b JY |
126 | |
127 | mutex_unlock(&kbdev->pm.lock); | |
128 | ||
129 | /* Now the policy change is finished, we release our fake context active | |
130 | * reference */ | |
131 | kbase_pm_context_idle(kbdev); | |
132 | } | |
133 | ||
134 | KBASE_EXPORT_TEST_API(kbase_pm_ca_set_policy); | |
135 | ||
136 | u64 kbase_pm_ca_get_core_mask(struct kbase_device *kbdev) | |
137 | { | |
dd8e48ad | 138 | lockdep_assert_held(&kbdev->hwaccess_lock); |
d25bc64b JY |
139 | |
140 | /* All cores must be enabled when instrumentation is in use */ | |
141 | if (kbdev->pm.backend.instr_enabled) | |
142 | return kbdev->gpu_props.props.raw_props.shader_present & | |
c2f86ae4 | 143 | kbdev->pm.debug_core_mask_all; |
d25bc64b JY |
144 | |
145 | if (kbdev->pm.backend.ca_current_policy == NULL) | |
146 | return kbdev->gpu_props.props.raw_props.shader_present & | |
c2f86ae4 | 147 | kbdev->pm.debug_core_mask_all; |
d25bc64b JY |
148 | |
149 | return kbdev->pm.backend.ca_current_policy->get_core_mask(kbdev) & | |
c2f86ae4 | 150 | kbdev->pm.debug_core_mask_all; |
d25bc64b JY |
151 | } |
152 | ||
153 | KBASE_EXPORT_TEST_API(kbase_pm_ca_get_core_mask); | |
154 | ||
155 | void kbase_pm_ca_update_core_status(struct kbase_device *kbdev, u64 cores_ready, | |
156 | u64 cores_transitioning) | |
157 | { | |
dd8e48ad | 158 | lockdep_assert_held(&kbdev->hwaccess_lock); |
d25bc64b JY |
159 | |
160 | if (kbdev->pm.backend.ca_current_policy != NULL) | |
161 | kbdev->pm.backend.ca_current_policy->update_core_status(kbdev, | |
162 | cores_ready, | |
163 | cores_transitioning); | |
164 | } | |
165 | ||
166 | void kbase_pm_ca_instr_enable(struct kbase_device *kbdev) | |
167 | { | |
168 | unsigned long flags; | |
169 | ||
dd8e48ad | 170 | spin_lock_irqsave(&kbdev->hwaccess_lock, flags); |
d25bc64b JY |
171 | kbdev->pm.backend.instr_enabled = true; |
172 | ||
173 | kbase_pm_update_cores_state_nolock(kbdev); | |
dd8e48ad | 174 | spin_unlock_irqrestore(&kbdev->hwaccess_lock, flags); |
d25bc64b JY |
175 | } |
176 | ||
177 | void kbase_pm_ca_instr_disable(struct kbase_device *kbdev) | |
178 | { | |
dd8e48ad | 179 | lockdep_assert_held(&kbdev->hwaccess_lock); |
d25bc64b JY |
180 | kbdev->pm.backend.instr_enabled = false; |
181 | ||
182 | kbase_pm_update_cores_state_nolock(kbdev); | |
d25bc64b | 183 | } |