On 17:08 Fri 12 Apr     , Peter Maydell wrote:
> We pass a ResetType argument to the Resettable class enter phase
> method, but we don't pass it to hold and exit, even though the
> callsites have it readily available.  This means that if a device
> cared about the ResetType it would need to record it in the enter
> phase method to use later on.  We should pass the type to all three
> of the phase methods to avoid having to do that.
> 
> This coccinelle script adds the ResetType argument to the hold and
> exit phases of the Resettable interface.
> 
> The first part of the script (rules holdfn_assigned, holdfn_defined,
> exitfn_assigned, exitfn_defined) update implementations of the
> interface within device models, both to change the signature of their
> method implementations and to pass on the reset type when they invoke
> reset on some other device.
> 
> The second part of the script is various special cases:
>  * method callsites in resettable_phase_hold(), resettable_phase_exit()
>    and device_phases_reset()
>  * updating the typedefs for the methods
>  * isl_pmbus_vr.c has some code where one device's reset method directly
>    calls the implementation of a different device's method
> 
> Signed-off-by: Peter Maydell <peter.mayd...@linaro.org>

Reviewed-by: Luc Michel <luc.mic...@amd.com>

(I'm not a coccinelle expert but LGTM)

> ---
> The structure here is a bit of an experiment: usually I would make
> the coccinelle script cover the main mechanical change and do the
> special cases by hand-editing. But I thought it might be clearer to
> have the entire next commit be made by coccinelle, so reviewers don't
> have to go hunting through a 99% automated commit for the 1% hand
> written part. Let me know whether you like this or not...
> ---
>  scripts/coccinelle/reset-type.cocci | 133 ++++++++++++++++++++++++++++
>  1 file changed, 133 insertions(+)
>  create mode 100644 scripts/coccinelle/reset-type.cocci
> 
> diff --git a/scripts/coccinelle/reset-type.cocci 
> b/scripts/coccinelle/reset-type.cocci
> new file mode 100644
> index 00000000000..14abdd7bd0c
> --- /dev/null
> +++ b/scripts/coccinelle/reset-type.cocci
> @@ -0,0 +1,133 @@
> +// Convert device code using three-phase reset to add a ResetType
> +// argument to implementations of ResettableHoldPhase and
> +// ResettableEnterPhase methods.
> +//
> +// Copyright Linaro Ltd 2024
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +//
> +// for dir in include hw target; do \
> +// spatch --macro-file scripts/cocci-macro-file.h \
> +//        --sp-file scripts/coccinelle/reset-type.cocci \
> +//        --keep-comments --smpl-spacing --in-place --include-headers \
> +//        --dir $dir; done
> +//
> +// This coccinelle script aims to produce a complete change that needs
> +// no human interaction, so as well as the generic "update device
> +// implementations of the hold and exit phase methods" it includes
> +// the special-case transformations needed for the core code and for
> +// one device model that does something a bit nonstandard. Those
> +// special cases are at the end of the file.
> +
> +// Look for where we use a function as a ResettableHoldPhase method,
> +// either by directly assigning it to phases.hold or by calling
> +// resettable_class_set_parent_phases, and remember the function name.
> +@ holdfn_assigned @
> +identifier enterfn, holdfn, exitfn;
> +identifier rc;
> +expression e;
> +@@
> +ResettableClass *rc;
> +...
> +(
> + rc->phases.hold = holdfn;
> +|
> + resettable_class_set_parent_phases(rc, enterfn, holdfn, exitfn, e);
> +)
> +
> +// Look for the definition of the function we found in holdfn_assigned,
> +// and add the new argument. If the function calls a hold function
> +// itself (probably chaining to the parent class reset) then add the
> +// new argument there too.
> +@ holdfn_defined @
> +identifier holdfn_assigned.holdfn;
> +typedef Object;
> +identifier obj;
> +expression parent;
> +@@
> +-holdfn(Object *obj)
> ++holdfn(Object *obj, ResetType type)
> +{
> +    <...
> +-    parent.hold(obj)
> ++    parent.hold(obj, type)
> +    ...>
> +}
> +
> +// Similarly for ResettableExitPhase.
> +@ exitfn_assigned @
> +identifier enterfn, holdfn, exitfn;
> +identifier rc;
> +expression e;
> +@@
> +ResettableClass *rc;
> +...
> +(
> + rc->phases.exit = exitfn;
> +|
> + resettable_class_set_parent_phases(rc, enterfn, holdfn, exitfn, e);
> +)
> +@ exitfn_defined @
> +identifier exitfn_assigned.exitfn;
> +typedef Object;
> +identifier obj;
> +expression parent;
> +@@
> +-exitfn(Object *obj)
> ++exitfn(Object *obj, ResetType type)
> +{
> +    <...
> +-    parent.exit(obj)
> ++    parent.exit(obj, type)
> +    ...>
> +}
> +
> +// SPECIAL CASES ONLY BELOW HERE
> +// We use a python scripted constraint on the position of the match
> +// to ensure that they only match in a particular function. See
> +// https://public-inbox.org/git/alpine.DEB.2.21.1808240652370.2344@hadrien/
> +// which recommends this as the way to do "match only in this function".
> +
> +// Special case: isl_pmbus_vr.c has some reset methods calling others 
> directly
> +@ isl_pmbus_vr @
> +identifier obj;
> +@@
> +- isl_pmbus_vr_exit_reset(obj);
> ++ isl_pmbus_vr_exit_reset(obj, type);
> +
> +// Special case: device_phases_reset() needs to pass RESET_TYPE_COLD
> +@ device_phases_reset_hold @
> +expression obj;
> +identifier rc;
> +identifier phase;
> +position p : script:python() { p[0].current_element == "device_phases_reset" 
> };
> +@@
> +- rc->phases.phase(obj)@p
> ++ rc->phases.phase(obj, RESET_TYPE_COLD)
> +
> +// Special case: in resettable_phase_hold() and resettable_phase_exit()
> +// we need to pass through the ResetType argument to the method being called
> +@ resettable_phase_hold @
> +expression obj;
> +identifier rc;
> +position p : script:python() { p[0].current_element == 
> "resettable_phase_hold" };
> +@@
> +- rc->phases.hold(obj)@p
> ++ rc->phases.hold(obj, type)
> +@ resettable_phase_exit @
> +expression obj;
> +identifier rc;
> +position p : script:python() { p[0].current_element == 
> "resettable_phase_exit" };
> +@@
> +- rc->phases.exit(obj)@p
> ++ rc->phases.exit(obj, type)
> +// Special case: the typedefs for the methods need to declare the new 
> argument
> +@ phase_typedef_hold @
> +identifier obj;
> +@@
> +- typedef void (*ResettableHoldPhase)(Object *obj);
> ++ typedef void (*ResettableHoldPhase)(Object *obj, ResetType type);
> +@ phase_typedef_exit @
> +identifier obj;
> +@@
> +- typedef void (*ResettableExitPhase)(Object *obj);
> ++ typedef void (*ResettableExitPhase)(Object *obj, ResetType type);
> --
> 2.34.1
> 
> 

-- 

Reply via email to