1// Convert device code using three-phase reset to add a ResetType
2// argument to implementations of ResettableHoldPhase and
3// ResettableEnterPhase methods.
4//
5// Copyright Linaro Ltd 2024
6// SPDX-License-Identifier: GPL-2.0-or-later
7//
8// for dir in include hw target; do \
9// spatch --macro-file scripts/cocci-macro-file.h \
10//        --sp-file scripts/coccinelle/reset-type.cocci \
11//        --keep-comments --smpl-spacing --in-place --include-headers \
12//        --dir $dir; done
13//
14// This coccinelle script aims to produce a complete change that needs
15// no human interaction, so as well as the generic "update device
16// implementations of the hold and exit phase methods" it includes
17// the special-case transformations needed for the core code and for
18// one device model that does something a bit nonstandard. Those
19// special cases are at the end of the file.
20
21// Look for where we use a function as a ResettableHoldPhase method,
22// either by directly assigning it to phases.hold or by calling
23// resettable_class_set_parent_phases, and remember the function name.
24@ holdfn_assigned @
25identifier enterfn, holdfn, exitfn;
26identifier rc;
27expression e;
28@@
29ResettableClass *rc;
30...
31(
32 rc->phases.hold = holdfn;
33|
34 resettable_class_set_parent_phases(rc, enterfn, holdfn, exitfn, e);
35)
36
37// Look for the definition of the function we found in holdfn_assigned,
38// and add the new argument. If the function calls a hold function
39// itself (probably chaining to the parent class reset) then add the
40// new argument there too.
41@ holdfn_defined @
42identifier holdfn_assigned.holdfn;
43typedef Object;
44identifier obj;
45expression parent;
46@@
47-holdfn(Object *obj)
48+holdfn(Object *obj, ResetType type)
49{
50    <...
51-    parent.hold(obj)
52+    parent.hold(obj, type)
53    ...>
54}
55
56// Similarly for ResettableExitPhase.
57@ exitfn_assigned @
58identifier enterfn, holdfn, exitfn;
59identifier rc;
60expression e;
61@@
62ResettableClass *rc;
63...
64(
65 rc->phases.exit = exitfn;
66|
67 resettable_class_set_parent_phases(rc, enterfn, holdfn, exitfn, e);
68)
69@ exitfn_defined @
70identifier exitfn_assigned.exitfn;
71typedef Object;
72identifier obj;
73expression parent;
74@@
75-exitfn(Object *obj)
76+exitfn(Object *obj, ResetType type)
77{
78    <...
79-    parent.exit(obj)
80+    parent.exit(obj, type)
81    ...>
82}
83
84// SPECIAL CASES ONLY BELOW HERE
85// We use a python scripted constraint on the position of the match
86// to ensure that they only match in a particular function. See
87// https://public-inbox.org/git/alpine.DEB.2.21.1808240652370.2344@hadrien/
88// which recommends this as the way to do "match only in this function".
89
90// Special case: isl_pmbus_vr.c has some reset methods calling others directly
91@ isl_pmbus_vr @
92identifier obj;
93@@
94- isl_pmbus_vr_exit_reset(obj);
95+ isl_pmbus_vr_exit_reset(obj, type);
96
97// Special case: device_phases_reset() needs to pass RESET_TYPE_COLD
98@ device_phases_reset_hold @
99expression obj;
100identifier rc;
101identifier phase;
102position p : script:python() { p[0].current_element == "device_phases_reset" };
103@@
104- rc->phases.phase(obj)@p
105+ rc->phases.phase(obj, RESET_TYPE_COLD)
106
107// Special case: in resettable_phase_hold() and resettable_phase_exit()
108// we need to pass through the ResetType argument to the method being called
109@ resettable_phase_hold @
110expression obj;
111identifier rc;
112position p : script:python() { p[0].current_element == "resettable_phase_hold" };
113@@
114- rc->phases.hold(obj)@p
115+ rc->phases.hold(obj, type)
116@ resettable_phase_exit @
117expression obj;
118identifier rc;
119position p : script:python() { p[0].current_element == "resettable_phase_exit" };
120@@
121- rc->phases.exit(obj)@p
122+ rc->phases.exit(obj, type)
123// Special case: the typedefs for the methods need to declare the new argument
124@ phase_typedef_hold @
125identifier obj;
126@@
127- typedef void (*ResettableHoldPhase)(Object *obj);
128+ typedef void (*ResettableHoldPhase)(Object *obj, ResetType type);
129@ phase_typedef_exit @
130identifier obj;
131@@
132- typedef void (*ResettableExitPhase)(Object *obj);
133+ typedef void (*ResettableExitPhase)(Object *obj, ResetType type);
134