aboutsummaryrefslogtreecommitdiff
path: root/drivers/gpu/arm/t6xx/kbase/src/common/mali_kbase_pm_ca.c
blob: 39310d7607f1acf07346573e32ea5d4f9cc03b54 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 *
 * (C) COPYRIGHT 2013 ARM Limited. All rights reserved.
 *
 * This program is free software and is provided to you under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation, and any use by you of this program is subject to the terms
 * of such GNU licence.
 *
 * A copy of the licence is included with the program, and can also be obtained
 * from Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 * Boston, MA  02110-1301, USA.
 *
 */



/**
 * @file mali_kbase_pm_ca.c
 * Base kernel core availability APIs
 */

#include <kbase/src/common/mali_kbase.h>
#include <kbase/src/common/mali_kbase_pm.h>

extern const kbase_pm_ca_policy kbase_pm_ca_fixed_policy_ops;
#if MALI_CUSTOMER_RELEASE == 0
extern const kbase_pm_ca_policy kbase_pm_ca_random_policy_ops;
#endif

static const kbase_pm_ca_policy *const policy_list[] = {
	&kbase_pm_ca_fixed_policy_ops,
#if MALI_CUSTOMER_RELEASE == 0
	&kbase_pm_ca_random_policy_ops
#endif
};

/** The number of policies available in the system.
 *  This is derived from the number of functions listed in policy_get_functions.
 */
#define POLICY_COUNT (sizeof(policy_list)/sizeof(*policy_list))

mali_error kbase_pm_ca_init(kbase_device *kbdev)
{
	KBASE_DEBUG_ASSERT(kbdev != NULL);

	kbdev->pm.ca_current_policy = policy_list[0];

	kbdev->pm.ca_current_policy->init(kbdev);

	return MALI_ERROR_NONE;
}

void kbase_pm_ca_term(kbase_device *kbdev)
{
	kbdev->pm.ca_current_policy->term(kbdev);
}

int kbase_pm_ca_list_policies(const kbase_pm_ca_policy * const **list)
{
	if (!list)
		return POLICY_COUNT;

	*list = policy_list;

	return POLICY_COUNT;
}

KBASE_EXPORT_TEST_API(kbase_pm_ca_list_policies)

const kbase_pm_ca_policy *kbase_pm_ca_get_policy(kbase_device *kbdev)
{
	KBASE_DEBUG_ASSERT(kbdev != NULL);

	return kbdev->pm.ca_current_policy;
}

KBASE_EXPORT_TEST_API(kbase_pm_ca_get_policy)

void kbase_pm_ca_set_policy(kbase_device *kbdev, const kbase_pm_ca_policy *new_policy)
{
	const kbase_pm_ca_policy *old_policy;
	unsigned long flags;

	KBASE_DEBUG_ASSERT(kbdev != NULL);
	KBASE_DEBUG_ASSERT(new_policy != NULL);

	KBASE_TRACE_ADD(kbdev, PM_CA_SET_POLICY, NULL, NULL, 0u, new_policy->id);

	/* During a policy change we pretend the GPU is active */
	/* A suspend won't happen here, because we're in a syscall from a userspace thread */
	kbase_pm_context_active(kbdev);

	mutex_lock(&kbdev->pm.lock);

	/* Remove the policy to prevent IRQ handlers from working on it */
	spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
	old_policy = kbdev->pm.ca_current_policy;
	kbdev->pm.ca_current_policy = NULL;
	spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);

	if (old_policy->term)
		old_policy->term(kbdev);

	if (new_policy->init)
		new_policy->init(kbdev);

	spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
	kbdev->pm.ca_current_policy = new_policy;

	/* If any core power state changes were previously attempted, but couldn't
	 * be made because the policy was changing (current_policy was NULL), then
	 * re-try them here. */
	kbase_pm_update_cores_state_nolock(kbdev);

	kbdev->pm.ca_current_policy->update_core_status(kbdev, kbdev->shader_ready_bitmap, kbdev->shader_transitioning_bitmap);

	spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);

	mutex_unlock(&kbdev->pm.lock);

	/* Now the policy change is finished, we release our fake context active reference */
	kbase_pm_context_idle(kbdev);
}

KBASE_EXPORT_TEST_API(kbase_pm_ca_set_policy)

u64 kbase_pm_ca_get_core_mask(kbase_device *kbdev)
{
	lockdep_assert_held(&kbdev->pm.power_change_lock);

	/* All cores must be enabled when instrumentation is in use */
	if (kbdev->pm.instr_enabled == MALI_TRUE)
		return kbdev->shader_present_bitmap & kbdev->pm.debug_core_mask;

	if (kbdev->pm.ca_current_policy == NULL)
		return kbdev->shader_present_bitmap & kbdev->pm.debug_core_mask;

	return kbdev->pm.ca_current_policy->get_core_mask(kbdev) & kbdev->pm.debug_core_mask;
}

KBASE_EXPORT_TEST_API(kbase_pm_ca_get_core_mask)

void kbase_pm_ca_update_core_status(kbase_device *kbdev, u64 cores_ready, u64 cores_transitioning)
{
	lockdep_assert_held(&kbdev->pm.power_change_lock);

	if (kbdev->pm.ca_current_policy != NULL)
		kbdev->pm.ca_current_policy->update_core_status(kbdev, cores_ready, cores_transitioning);
}

void kbase_pm_ca_instr_enable(struct kbase_device *kbdev)
{
	unsigned long flags;

	spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
	kbdev->pm.instr_enabled = MALI_TRUE;

	kbase_pm_update_cores_state_nolock(kbdev);
	spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
}

void kbase_pm_ca_instr_disable(struct kbase_device *kbdev)
{
	unsigned long flags;

	spin_lock_irqsave(&kbdev->pm.power_change_lock, flags);
	kbdev->pm.instr_enabled = MALI_FALSE;

	kbase_pm_update_cores_state_nolock(kbdev);
	spin_unlock_irqrestore(&kbdev->pm.power_change_lock, flags);
}