qemu/include/hw/resettable.h
Damien Hedde bc5a39bf26 hw/core: create Resettable QOM interface
This commit defines an interface allowing multi-phase reset. This aims
to solve a problem of the actual single-phase reset (built in
DeviceClass and BusClass): reset behavior is dependent on the order
in which reset handlers are called. In particular doing external
side-effect (like setting an qemu_irq) is problematic because receiving
object may not be reset yet.

The Resettable interface divides the reset in 3 well defined phases.
To reset an object tree, all 1st phases are executed then all 2nd then
all 3rd. See the comments in include/hw/resettable.h for a more complete
description. The interface defines 3 phases to let the future
possibility of holding an object into reset for some time.

The qdev/qbus reset in DeviceClass and BusClass will be modified in
following commits to use this interface. A mechanism is provided
to allow executing a transitional reset handler in place of the 2nd
phase which is executed in children-then-parent order inside a tree.
This will allow to transition devices and buses smoothly while
keeping the exact current qdev/qbus reset behavior for now.

Documentation will be added in a following commit.

Signed-off-by: Damien Hedde <damien.hedde@greensocs.com>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Tested-by: Philippe Mathieu-Daudé <philmd@redhat.com>
Message-id: 20200123132823.1117486-4-damien.hedde@greensocs.com
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
2020-01-30 16:02:03 +00:00

212 lines
7.9 KiB
C

/*
* Resettable interface header.
*
* Copyright (c) 2019 GreenSocs SAS
*
* Authors:
* Damien Hedde
*
* This work is licensed under the terms of the GNU GPL, version 2 or later.
* See the COPYING file in the top-level directory.
*/
#ifndef HW_RESETTABLE_H
#define HW_RESETTABLE_H
#include "qom/object.h"
#define TYPE_RESETTABLE_INTERFACE "resettable"
#define RESETTABLE_CLASS(class) \
OBJECT_CLASS_CHECK(ResettableClass, (class), TYPE_RESETTABLE_INTERFACE)
#define RESETTABLE_GET_CLASS(obj) \
OBJECT_GET_CLASS(ResettableClass, (obj), TYPE_RESETTABLE_INTERFACE)
typedef struct ResettableState ResettableState;
/**
* ResetType:
* Types of reset.
*
* + Cold: reset resulting from a power cycle of the object.
*
* TODO: Support has to be added to handle more types. In particular,
* ResettableState structure needs to be expanded.
*/
typedef enum ResetType {
RESET_TYPE_COLD,
} ResetType;
/*
* ResettableClass:
* Interface for resettable objects.
*
* See docs/devel/reset.rst for more detailed information about how QEMU models
* reset. This whole API must only be used when holding the iothread mutex.
*
* All objects which can be reset must implement this interface;
* it is usually provided by a base class such as DeviceClass or BusClass.
* Every Resettable object must maintain some state tracking the
* progress of a reset operation by providing a ResettableState structure.
* The functions defined in this module take care of updating the
* state of the reset.
* The base class implementation of the interface provides this
* state and implements the associated method: get_state.
*
* Concrete object implementations (typically specific devices
* such as a UART model) should provide the functions
* for the phases.enter, phases.hold and phases.exit methods, which
* they can set in their class init function, either directly or
* by calling resettable_class_set_parent_phases().
* The phase methods are guaranteed to only only ever be called once
* for any reset event, in the order 'enter', 'hold', 'exit'.
* An object will always move quickly from 'enter' to 'hold'
* but might remain in 'hold' for an arbitrary period of time
* before eventually reset is deasserted and the 'exit' phase is called.
* Object implementations should be prepared for functions handling
* inbound connections from other devices (such as qemu_irq handler
* functions) to be called at any point during reset after their
* 'enter' method has been called.
*
* Users of a resettable object should not call these methods
* directly, but instead use the function resettable_reset().
*
* @phases.enter: This phase is called when the object enters reset. It
* should reset local state of the object, but it must not do anything that
* has a side-effect on other objects, such as raising or lowering a qemu_irq
* line or reading or writing guest memory. It takes the reset's type as
* argument.
*
* @phases.hold: This phase is called for entry into reset, once every object
* in the system which is being reset has had its @phases.enter method called.
* At this point devices can do actions that affect other objects.
*
* @phases.exit: This phase is called when the object leaves the reset state.
* Actions affecting other objects are permitted.
*
* @get_state: Mandatory method which must return a pointer to a
* ResettableState.
*
* @get_transitional_function: transitional method to handle Resettable objects
* not yet fully moved to this interface. It will be removed as soon as it is
* not needed anymore. This method is optional and may return a pointer to a
* function to be used instead of the phases. If the method exists and returns
* a non-NULL function pointer then that function is executed as a replacement
* of the 'hold' phase method taking the object as argument. The two other phase
* methods are not executed.
*
* @child_foreach: Executes a given callback on every Resettable child. Child
* in this context means a child in the qbus tree, so the children of a qbus
* are the devices on it, and the children of a device are all the buses it
* owns. This is not the same as the QOM object hierarchy. The function takes
* additional opaque and ResetType arguments which must be passed unmodified to
* the callback.
*/
typedef void (*ResettableEnterPhase)(Object *obj, ResetType type);
typedef void (*ResettableHoldPhase)(Object *obj);
typedef void (*ResettableExitPhase)(Object *obj);
typedef ResettableState * (*ResettableGetState)(Object *obj);
typedef void (*ResettableTrFunction)(Object *obj);
typedef ResettableTrFunction (*ResettableGetTrFunction)(Object *obj);
typedef void (*ResettableChildCallback)(Object *, void *opaque,
ResetType type);
typedef void (*ResettableChildForeach)(Object *obj,
ResettableChildCallback cb,
void *opaque, ResetType type);
typedef struct ResettablePhases {
ResettableEnterPhase enter;
ResettableHoldPhase hold;
ResettableExitPhase exit;
} ResettablePhases;
typedef struct ResettableClass {
InterfaceClass parent_class;
/* Phase methods */
ResettablePhases phases;
/* State access method */
ResettableGetState get_state;
/* Transitional method for legacy reset compatibility */
ResettableGetTrFunction get_transitional_function;
/* Hierarchy handling method */
ResettableChildForeach child_foreach;
} ResettableClass;
/**
* ResettableState:
* Structure holding reset related state. The fields should not be accessed
* directly; the definition is here to allow further inclusion into other
* objects.
*
* @count: Number of reset level the object is into. It is incremented when
* the reset operation starts and decremented when it finishes.
* @hold_phase_pending: flag which indicates that we need to invoke the 'hold'
* phase handler for this object.
* @exit_phase_in_progress: true if we are currently in the exit phase
*/
struct ResettableState {
unsigned count;
bool hold_phase_pending;
bool exit_phase_in_progress;
};
/**
* resettable_reset:
* Trigger a reset on an object @obj of type @type. @obj must implement
* Resettable interface.
*
* Calling this function is equivalent to calling @resettable_assert_reset()
* then @resettable_release_reset().
*/
void resettable_reset(Object *obj, ResetType type);
/**
* resettable_assert_reset:
* Put an object @obj into reset. @obj must implement Resettable interface.
*
* @resettable_release_reset() must eventually be called after this call.
* There must be one call to @resettable_release_reset() per call of
* @resettable_assert_reset(), with the same type argument.
*
* NOTE: Until support for migration is added, the @resettable_release_reset()
* must not be delayed. It must occur just after @resettable_assert_reset() so
* that migration cannot be triggered in between. Prefer using
* @resettable_reset() for now.
*/
void resettable_assert_reset(Object *obj, ResetType type);
/**
* resettable_release_reset:
* Release the object @obj from reset. @obj must implement Resettable interface.
*
* See @resettable_assert_reset() description for details.
*/
void resettable_release_reset(Object *obj, ResetType type);
/**
* resettable_is_in_reset:
* Return true if @obj is under reset.
*
* @obj must implement Resettable interface.
*/
bool resettable_is_in_reset(Object *obj);
/**
* resettable_class_set_parent_phases:
*
* Save @rc current reset phases into @parent_phases and override @rc phases
* by the given new methods (@enter, @hold and @exit).
* Each phase is overridden only if the new one is not NULL allowing to
* override a subset of phases.
*/
void resettable_class_set_parent_phases(ResettableClass *rc,
ResettableEnterPhase enter,
ResettableHoldPhase hold,
ResettableExitPhase exit,
ResettablePhases *parent_phases);
#endif