1
2
3
4
5
6
7
8
9
10
11
12
13#include "qemu/osdep.h"
14#include "qemu/module.h"
15#include "hw/resettable.h"
16#include "trace.h"
17
18
19
20
21
22
23static void resettable_phase_enter(Object *obj, void *opaque, ResetType type);
24static void resettable_phase_hold(Object *obj, void *opaque, ResetType type);
25static void resettable_phase_exit(Object *obj, void *opaque, ResetType type);
26
27
28
29
30
31
32
33
34
35
36
37
38
39static bool enter_phase_in_progress;
40static unsigned exit_phase_in_progress;
41
42void resettable_reset(Object *obj, ResetType type)
43{
44 trace_resettable_reset(obj, type);
45 resettable_assert_reset(obj, type);
46 resettable_release_reset(obj, type);
47}
48
49void resettable_assert_reset(Object *obj, ResetType type)
50{
51
52 assert(type == RESET_TYPE_COLD);
53 trace_resettable_reset_assert_begin(obj, type);
54 assert(!enter_phase_in_progress);
55
56 enter_phase_in_progress = true;
57 resettable_phase_enter(obj, NULL, type);
58 enter_phase_in_progress = false;
59
60 resettable_phase_hold(obj, NULL, type);
61
62 trace_resettable_reset_assert_end(obj);
63}
64
65void resettable_release_reset(Object *obj, ResetType type)
66{
67
68 assert(type == RESET_TYPE_COLD);
69 trace_resettable_reset_release_begin(obj, type);
70 assert(!enter_phase_in_progress);
71
72 exit_phase_in_progress += 1;
73 resettable_phase_exit(obj, NULL, type);
74 exit_phase_in_progress -= 1;
75
76 trace_resettable_reset_release_end(obj);
77}
78
79bool resettable_is_in_reset(Object *obj)
80{
81 ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
82 ResettableState *s = rc->get_state(obj);
83
84 return s->count > 0;
85}
86
87
88
89
90
91static void resettable_child_foreach(ResettableClass *rc, Object *obj,
92 ResettableChildCallback cb,
93 void *opaque, ResetType type)
94{
95 if (rc->child_foreach) {
96 rc->child_foreach(obj, cb, opaque, type);
97 }
98}
99
100
101
102
103
104static ResettableTrFunction resettable_get_tr_func(ResettableClass *rc,
105 Object *obj)
106{
107 ResettableTrFunction tr_func = NULL;
108 if (rc->get_transitional_function) {
109 tr_func = rc->get_transitional_function(obj);
110 }
111 return tr_func;
112}
113
114static void resettable_phase_enter(Object *obj, void *opaque, ResetType type)
115{
116 ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
117 ResettableState *s = rc->get_state(obj);
118 const char *obj_typename = object_get_typename(obj);
119 bool action_needed = false;
120
121
122 assert(!s->exit_phase_in_progress);
123
124 trace_resettable_phase_enter_begin(obj, obj_typename, s->count, type);
125
126
127
128
129
130
131 if (s->count++ == 0) {
132 action_needed = true;
133 }
134
135
136
137
138
139
140
141 assert(s->count <= 50);
142
143
144
145
146
147 resettable_child_foreach(rc, obj, resettable_phase_enter, NULL, type);
148
149
150 if (action_needed) {
151 trace_resettable_phase_enter_exec(obj, obj_typename, type,
152 !!rc->phases.enter);
153 if (rc->phases.enter && !resettable_get_tr_func(rc, obj)) {
154 rc->phases.enter(obj, type);
155 }
156 s->hold_phase_pending = true;
157 }
158 trace_resettable_phase_enter_end(obj, obj_typename, s->count);
159}
160
161static void resettable_phase_hold(Object *obj, void *opaque, ResetType type)
162{
163 ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
164 ResettableState *s = rc->get_state(obj);
165 const char *obj_typename = object_get_typename(obj);
166
167
168 assert(!s->exit_phase_in_progress);
169
170 trace_resettable_phase_hold_begin(obj, obj_typename, s->count, type);
171
172
173 resettable_child_foreach(rc, obj, resettable_phase_hold, NULL, type);
174
175
176 if (s->hold_phase_pending) {
177 s->hold_phase_pending = false;
178 ResettableTrFunction tr_func = resettable_get_tr_func(rc, obj);
179 trace_resettable_phase_hold_exec(obj, obj_typename, !!rc->phases.hold);
180 if (tr_func) {
181 trace_resettable_transitional_function(obj, obj_typename);
182 tr_func(obj);
183 } else if (rc->phases.hold) {
184 rc->phases.hold(obj);
185 }
186 }
187 trace_resettable_phase_hold_end(obj, obj_typename, s->count);
188}
189
190static void resettable_phase_exit(Object *obj, void *opaque, ResetType type)
191{
192 ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
193 ResettableState *s = rc->get_state(obj);
194 const char *obj_typename = object_get_typename(obj);
195
196 assert(!s->exit_phase_in_progress);
197 trace_resettable_phase_exit_begin(obj, obj_typename, s->count, type);
198
199
200 s->exit_phase_in_progress = true;
201 resettable_child_foreach(rc, obj, resettable_phase_exit, NULL, type);
202
203 assert(s->count > 0);
204 if (s->count == 1) {
205 trace_resettable_phase_exit_exec(obj, obj_typename, !!rc->phases.exit);
206 if (rc->phases.exit && !resettable_get_tr_func(rc, obj)) {
207 rc->phases.exit(obj);
208 }
209 s->count = 0;
210 }
211 s->exit_phase_in_progress = false;
212 trace_resettable_phase_exit_end(obj, obj_typename, s->count);
213}
214
215
216
217
218
219static unsigned resettable_get_count(Object *obj)
220{
221 if (obj) {
222 ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
223 return rc->get_state(obj)->count;
224 }
225 return 0;
226}
227
228void resettable_change_parent(Object *obj, Object *newp, Object *oldp)
229{
230 ResettableClass *rc = RESETTABLE_GET_CLASS(obj);
231 ResettableState *s = rc->get_state(obj);
232 unsigned newp_count = resettable_get_count(newp);
233 unsigned oldp_count = resettable_get_count(oldp);
234
235
236
237
238
239
240
241
242
243 assert(!enter_phase_in_progress && !exit_phase_in_progress);
244 trace_resettable_change_parent(obj, oldp, oldp_count, newp, newp_count);
245
246
247
248
249
250
251 for (unsigned i = oldp_count; i < newp_count; i++) {
252 resettable_assert_reset(obj, RESET_TYPE_COLD);
253 }
254
255
256
257
258 if (oldp_count && s->hold_phase_pending) {
259 resettable_phase_hold(obj, NULL, RESET_TYPE_COLD);
260 }
261
262 for (unsigned i = newp_count; i < oldp_count; i++) {
263 resettable_release_reset(obj, RESET_TYPE_COLD);
264 }
265}
266
267void resettable_cold_reset_fn(void *opaque)
268{
269 resettable_reset((Object *) opaque, RESET_TYPE_COLD);
270}
271
272void resettable_class_set_parent_phases(ResettableClass *rc,
273 ResettableEnterPhase enter,
274 ResettableHoldPhase hold,
275 ResettableExitPhase exit,
276 ResettablePhases *parent_phases)
277{
278 *parent_phases = rc->phases;
279 if (enter) {
280 rc->phases.enter = enter;
281 }
282 if (hold) {
283 rc->phases.hold = hold;
284 }
285 if (exit) {
286 rc->phases.exit = exit;
287 }
288}
289
290static const TypeInfo resettable_interface_info = {
291 .name = TYPE_RESETTABLE_INTERFACE,
292 .parent = TYPE_INTERFACE,
293 .class_size = sizeof(ResettableClass),
294};
295
296static void reset_register_types(void)
297{
298 type_register_static(&resettable_interface_info);
299}
300
301type_init(reset_register_types)
302