Message ID | 20200225131422.53368-5-damien.hedde@greensocs.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Clock framework API | expand |
On Tue, Feb 25, 2020 at 5:56 AM Damien Hedde <damien.hedde@greensocs.com> wrote: > > Introduce a function and macro helpers to setup several clocks > in a device from a static array description. > > An element of the array describes the clock (name and direction) as > well as the related callback and an optional offset to store the > created object pointer in the device state structure. > > The array must be terminated by a special element QDEV_CLOCK_END. > > This is based on the original work of Frederic Konrad. > > Signed-off-by: Damien Hedde <damien.hedde@greensocs.com> > Reviewed-by: Philippe Mathieu-Daudé <philmd@redhat.com> Reviewed-by: Alistair Francis <alistair.francis@wdc.com> Alistair > -- > > v7: > + update ClockIn/Out types > + remove the QDEV_CLOCK_IN_NOFIELD macro > + remove leading underscores in macro arguments (Peter) > + updated some comments (Peter) > + removed trivial asserts (Peter) > --- > include/hw/qdev-clock.h | 55 +++++++++++++++++++++++++++++++++++++++++ > hw/core/qdev-clock.c | 17 +++++++++++++ > 2 files changed, 72 insertions(+) > > diff --git a/include/hw/qdev-clock.h b/include/hw/qdev-clock.h > index b3b3a3e021..a340f65ff9 100644 > --- a/include/hw/qdev-clock.h > +++ b/include/hw/qdev-clock.h > @@ -101,4 +101,59 @@ Clock *qdev_alias_clock(DeviceState *dev, const char *name, > */ > void qdev_finalize_clocklist(DeviceState *dev); > > +/** > + * ClockPortInitElem: > + * @name: name of the clock (can't be NULL) > + * @output: indicates whether the clock is input or output > + * @callback: for inputs, optional callback to be called on clock's update > + * with device as opaque > + * @offset: optional offset to store the ClockIn or ClockOut pointer in device > + * state structure (0 means unused) > + */ > +struct ClockPortInitElem { > + const char *name; > + bool is_output; > + ClockCallback *callback; > + size_t offset; > +}; > + > +#define clock_offset_value(devstate, field) \ > + (offsetof(devstate, field) + \ > + type_check(Clock *, typeof_field(devstate, field))) > + > +#define QDEV_CLOCK(out_not_in, devstate, field, cb) { \ > + .name = (stringify(field)), \ > + .is_output = out_not_in, \ > + .callback = cb, \ > + .offset = clock_offset_value(devstate, field), \ > +} > + > +/** > + * QDEV_CLOCK_(IN|OUT): > + * @devstate: structure type. @dev argument of qdev_init_clocks below must be > + * a pointer to that same type. > + * @field: a field in @_devstate (must be Clock*) > + * @callback: (for input only) callback (or NULL) to be called with the device > + * state as argument > + * > + * The name of the clock will be derived from @field > + */ > +#define QDEV_CLOCK_IN(devstate, field, callback) \ > + QDEV_CLOCK(false, devstate, field, callback) > + > +#define QDEV_CLOCK_OUT(devstate, field) \ > + QDEV_CLOCK(true, devstate, field, NULL) > + > +#define QDEV_CLOCK_END { .name = NULL } > + > +typedef struct ClockPortInitElem ClockPortInitArray[]; > + > +/** > + * qdev_init_clocks: > + * @dev: the device to add clocks to > + * @clocks: a QDEV_CLOCK_END-terminated array which contains the > + * clocks information. > + */ > +void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks); > + > #endif /* QDEV_CLOCK_H */ > diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c > index 62035aef83..a94cc44437 100644 > --- a/hw/core/qdev-clock.c > +++ b/hw/core/qdev-clock.c > @@ -116,6 +116,23 @@ Clock *qdev_init_clock_in(DeviceState *dev, const char *name, > return ncl->clock; > } > > +void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks) > +{ > + const struct ClockPortInitElem *elem; > + > + for (elem = &clocks[0]; elem->name != NULL; elem++) { > + Clock **clkp; > + /* offset cannot be inside the DeviceState part */ > + assert(elem->offset > sizeof(DeviceState)); > + clkp = (Clock **)(((void *) dev) + elem->offset); > + if (elem->is_output) { > + *clkp = qdev_init_clock_out(dev, elem->name); > + } else { > + *clkp = qdev_init_clock_in(dev, elem->name, elem->callback, dev); > + } > + } > +} > + > static NamedClockList *qdev_get_clocklist(DeviceState *dev, const char *name) > { > NamedClockList *ncl; > -- > 2.25.1 > >
diff --git a/include/hw/qdev-clock.h b/include/hw/qdev-clock.h index b3b3a3e021..a340f65ff9 100644 --- a/include/hw/qdev-clock.h +++ b/include/hw/qdev-clock.h @@ -101,4 +101,59 @@ Clock *qdev_alias_clock(DeviceState *dev, const char *name, */ void qdev_finalize_clocklist(DeviceState *dev); +/** + * ClockPortInitElem: + * @name: name of the clock (can't be NULL) + * @output: indicates whether the clock is input or output + * @callback: for inputs, optional callback to be called on clock's update + * with device as opaque + * @offset: optional offset to store the ClockIn or ClockOut pointer in device + * state structure (0 means unused) + */ +struct ClockPortInitElem { + const char *name; + bool is_output; + ClockCallback *callback; + size_t offset; +}; + +#define clock_offset_value(devstate, field) \ + (offsetof(devstate, field) + \ + type_check(Clock *, typeof_field(devstate, field))) + +#define QDEV_CLOCK(out_not_in, devstate, field, cb) { \ + .name = (stringify(field)), \ + .is_output = out_not_in, \ + .callback = cb, \ + .offset = clock_offset_value(devstate, field), \ +} + +/** + * QDEV_CLOCK_(IN|OUT): + * @devstate: structure type. @dev argument of qdev_init_clocks below must be + * a pointer to that same type. + * @field: a field in @_devstate (must be Clock*) + * @callback: (for input only) callback (or NULL) to be called with the device + * state as argument + * + * The name of the clock will be derived from @field + */ +#define QDEV_CLOCK_IN(devstate, field, callback) \ + QDEV_CLOCK(false, devstate, field, callback) + +#define QDEV_CLOCK_OUT(devstate, field) \ + QDEV_CLOCK(true, devstate, field, NULL) + +#define QDEV_CLOCK_END { .name = NULL } + +typedef struct ClockPortInitElem ClockPortInitArray[]; + +/** + * qdev_init_clocks: + * @dev: the device to add clocks to + * @clocks: a QDEV_CLOCK_END-terminated array which contains the + * clocks information. + */ +void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks); + #endif /* QDEV_CLOCK_H */ diff --git a/hw/core/qdev-clock.c b/hw/core/qdev-clock.c index 62035aef83..a94cc44437 100644 --- a/hw/core/qdev-clock.c +++ b/hw/core/qdev-clock.c @@ -116,6 +116,23 @@ Clock *qdev_init_clock_in(DeviceState *dev, const char *name, return ncl->clock; } +void qdev_init_clocks(DeviceState *dev, const ClockPortInitArray clocks) +{ + const struct ClockPortInitElem *elem; + + for (elem = &clocks[0]; elem->name != NULL; elem++) { + Clock **clkp; + /* offset cannot be inside the DeviceState part */ + assert(elem->offset > sizeof(DeviceState)); + clkp = (Clock **)(((void *) dev) + elem->offset); + if (elem->is_output) { + *clkp = qdev_init_clock_out(dev, elem->name); + } else { + *clkp = qdev_init_clock_in(dev, elem->name, elem->callback, dev); + } + } +} + static NamedClockList *qdev_get_clocklist(DeviceState *dev, const char *name) { NamedClockList *ncl;