1 // © 2022 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #include <assert.h>
6 #include <hyptypes.h>
7 
8 #include <cpulocal.h>
9 #include <power.h>
10 #include <scheduler.h>
11 #include <thread.h>
12 
13 #if defined(INTERFACE_VCPU_RUN)
14 #include <vcpu.h>
15 #include <vcpu_run.h>
16 #endif
17 
18 #include "event_handlers.h"
19 
20 error_t
vcpu_power_handle_vcpu_poweron(thread_t * vcpu)21 vcpu_power_handle_vcpu_poweron(thread_t *vcpu)
22 {
23 	assert((vcpu != NULL) && !vcpu->vcpu_power_should_vote);
24 	vcpu->vcpu_power_should_vote = true;
25 
26 	cpu_index_t cpu	     = scheduler_get_affinity(vcpu);
27 	bool	    can_vote = cpulocal_index_valid(cpu);
28 
29 #if defined(INTERFACE_VCPU_RUN)
30 	if (vcpu_run_is_enabled(vcpu)) {
31 		can_vote = false;
32 	}
33 #endif
34 
35 	error_t ret;
36 	if (can_vote) {
37 		ret = power_vote_cpu_on(cpu);
38 	} else {
39 		ret = OK;
40 	}
41 
42 	return ret;
43 }
44 
45 error_t
vcpu_power_handle_vcpu_poweroff(thread_t * vcpu)46 vcpu_power_handle_vcpu_poweroff(thread_t *vcpu)
47 {
48 	assert((vcpu != NULL) && vcpu->vcpu_power_should_vote);
49 	vcpu->vcpu_power_should_vote = false;
50 
51 	cpu_index_t cpu	     = scheduler_get_affinity(vcpu);
52 	bool	    can_vote = cpulocal_index_valid(cpu);
53 #if defined(INTERFACE_VCPU_RUN)
54 	if (vcpu_run_is_enabled(vcpu)) {
55 		can_vote = false;
56 	}
57 #endif
58 
59 	if (can_vote) {
60 		power_vote_cpu_off(cpu);
61 	}
62 
63 	return OK;
64 }
65 
66 void
vcpu_power_handle_vcpu_stopped(void)67 vcpu_power_handle_vcpu_stopped(void)
68 {
69 	thread_t *vcpu = thread_get_self();
70 	assert((vcpu != NULL) && (vcpu->kind == THREAD_KIND_VCPU));
71 
72 	scheduler_lock_nopreempt(vcpu);
73 
74 	if (vcpu->vcpu_power_should_vote) {
75 		vcpu->vcpu_power_should_vote = false;
76 
77 		cpu_index_t cpu	     = scheduler_get_affinity(vcpu);
78 		bool	    can_vote = cpulocal_index_valid(cpu);
79 #if defined(INTERFACE_VCPU_RUN)
80 		if (vcpu_run_is_enabled(vcpu)) {
81 			can_vote = false;
82 		}
83 #endif
84 
85 		if (can_vote) {
86 			power_vote_cpu_off(cpu);
87 		}
88 	}
89 
90 	scheduler_unlock_nopreempt(vcpu);
91 }
92 
93 #if defined(INTERFACE_VCPU_RUN)
94 void
vcpu_power_handle_vcpu_run_enabled(thread_t * vcpu)95 vcpu_power_handle_vcpu_run_enabled(thread_t *vcpu)
96 {
97 	cpu_index_t cpu	     = scheduler_get_affinity(vcpu);
98 	bool	    can_vote = cpulocal_index_valid(cpu);
99 
100 	if (can_vote && vcpu->vcpu_power_should_vote) {
101 		power_vote_cpu_off(cpu);
102 	}
103 }
104 #endif
105 
106 error_t
vcpu_power_handle_scheduler_set_affinity_prepare(thread_t * vcpu,cpu_index_t prev_cpu,cpu_index_t next_cpu)107 vcpu_power_handle_scheduler_set_affinity_prepare(thread_t   *vcpu,
108 						 cpu_index_t prev_cpu,
109 						 cpu_index_t next_cpu)
110 {
111 	error_t ret = OK;
112 	assert(prev_cpu != next_cpu);
113 
114 	if (vcpu->kind != THREAD_KIND_VCPU) {
115 		goto out;
116 	}
117 
118 #if defined(INTERFACE_VCPU_RUN)
119 	if (vcpu_run_is_enabled(vcpu)) {
120 		goto out;
121 	}
122 #endif
123 
124 	if (vcpu->vcpu_power_should_vote) {
125 		if (cpulocal_index_valid(next_cpu)) {
126 			ret = power_vote_cpu_on(next_cpu);
127 		}
128 		if ((ret == OK) && cpulocal_index_valid(prev_cpu)) {
129 			power_vote_cpu_off(prev_cpu);
130 		}
131 	}
132 
133 out:
134 	return ret;
135 }
136