[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] hw/char/mchp_pfsoc_mmuart: QOM'ify PolarFire MMUART
From: |
Bin Meng |
Subject: |
Re: [PATCH] hw/char/mchp_pfsoc_mmuart: QOM'ify PolarFire MMUART |
Date: |
Sun, 26 Sep 2021 15:59:45 +0800 |
Hi Philippe,
On Thu, Sep 23, 2021 at 6:29 PM Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
>
> On 9/23/21 07:16, Bin Meng wrote:> On Sun, Sep 19, 2021 at 2:07 AM
> Philippe Mathieu-Daudé <f4bug@amsat.org> wrote:
> >>
> >> - Embed SerialMM in MchpPfSoCMMUartState and QOM-initialize it
> >> - Alias SERIAL_MM 'chardev' property on MCHP_PFSOC_UART
> >> - Forward SerialMM sysbus IRQ in mchp_pfsoc_mmuart_realize()
> >> - Keep mchp_pfsoc_mmuart_create() behavior
> >
> > Thanks for taking care of the updates!
> >
> >>
> >> Signed-off-by: Philippe Mathieu-Daudé <f4bug@amsat.org>
> >> ---
> >> include/hw/char/mchp_pfsoc_mmuart.h | 16 ++++--
> >> hw/char/mchp_pfsoc_mmuart.c | 77 +++++++++++++++++++++++------
> >> 2 files changed, 73 insertions(+), 20 deletions(-)
> >>
> >> diff --git a/include/hw/char/mchp_pfsoc_mmuart.h
> >> b/include/hw/char/mchp_pfsoc_mmuart.h
> >> index f61990215f0..b484b7ea5e4 100644
> >> --- a/include/hw/char/mchp_pfsoc_mmuart.h
> >> +++ b/include/hw/char/mchp_pfsoc_mmuart.h
> >> @@ -28,16 +28,22 @@
> >> #ifndef HW_MCHP_PFSOC_MMUART_H
> >> #define HW_MCHP_PFSOC_MMUART_H
> >>
> >> +#include "hw/sysbus.h"
> >> #include "hw/char/serial.h"
> >>
> >> #define MCHP_PFSOC_MMUART_REG_SIZE 52
> >>
> >> -typedef struct MchpPfSoCMMUartState {
> >> - MemoryRegion iomem;
> >> - hwaddr base;
> >> - qemu_irq irq;
> >> +#define TYPE_MCHP_PFSOC_UART "mchp.pfsoc.uart"
> >> +OBJECT_DECLARE_SIMPLE_TYPE(MchpPfSoCMMUartState, MCHP_PFSOC_UART)
> >>
> >> - SerialMM *serial;
> >> +typedef struct MchpPfSoCMMUartState {
> >> + /*< private >*/
> >> + SysBusDevice parent_obj;
> >> +
> >> + /*< public >*/
> >> + MemoryRegion iomem;
> >> +
> >> + SerialMM serial_mm;
> >>
> >> uint32_t reg[MCHP_PFSOC_MMUART_REG_SIZE / sizeof(uint32_t)];
> >> } MchpPfSoCMMUartState;
> >> diff --git a/hw/char/mchp_pfsoc_mmuart.c b/hw/char/mchp_pfsoc_mmuart.c
> >> index 2facf85c2d8..74404e047d4 100644
> >> --- a/hw/char/mchp_pfsoc_mmuart.c
> >> +++ b/hw/char/mchp_pfsoc_mmuart.c
> >> @@ -22,8 +22,9 @@
> >>
> >> #include "qemu/osdep.h"
> >> #include "qemu/log.h"
> >> -#include "chardev/char.h"
> >> +#include "qapi/error.h"
> >> #include "hw/char/mchp_pfsoc_mmuart.h"
> >> +#include "hw/qdev-properties.h"
> >>
> >> static uint64_t mchp_pfsoc_mmuart_read(void *opaque, hwaddr addr,
> >> unsigned size)
> >> {
> >> @@ -63,23 +64,69 @@ static const MemoryRegionOps mchp_pfsoc_mmuart_ops = {
> >> },
> >> };
> >>
> >> -MchpPfSoCMMUartState *mchp_pfsoc_mmuart_create(MemoryRegion *sysmem,
> >> - hwaddr base, qemu_irq irq, Chardev *chr)
> >> +static void mchp_pfsoc_mmuart_init(Object *obj)
> >> {
> >> - MchpPfSoCMMUartState *s;
> >> -
> >> - s = g_new0(MchpPfSoCMMUartState, 1);
> >> + SysBusDevice *sbd = SYS_BUS_DEVICE(obj);
> >> + MchpPfSoCMMUartState *s = MCHP_PFSOC_UART(obj);
> >>
> >> memory_region_init_io(&s->iomem, NULL, &mchp_pfsoc_mmuart_ops, s,
> >> "mchp.pfsoc.mmuart", 0x1000);
> >> + sysbus_init_mmio(sbd, &s->iomem);
> >>
> >> - s->base = base;
> >> - s->irq = irq;
> >> -
> >> - s->serial = serial_mm_init(sysmem, base, 2, irq, 399193, chr,
> >> - DEVICE_LITTLE_ENDIAN);
> >> -
> >> - memory_region_add_subregion(sysmem, base + 0x20, &s->iomem);
> >> -
> >> - return s;
> >> + object_initialize_child(obj, "serial-mm", &s->serial_mm,
> >> TYPE_SERIAL_MM);
> >> + object_property_add_alias(obj, "chardev", OBJECT(&s->serial_mm),
> >> "chardev");
> >
> > Do we have a common convention for what needs to be done in the
> > instance_init() call and what in the realize() call?
>
> No official convention IFAIK, but Peter & Markus described it in a
> thread 2 years ago, IIRC it was about the TYPE_ARMV7M model.
>
> See armv7m_instance_init() and armv7m_realize().
>
> stellaris_init() does:
>
> nvic = qdev_new(TYPE_ARMV7M);
> qdev_connect_clock_in(nvic, "cpuclk",
> qdev_get_clock_out(ssys_dev, "SYSCLK"));
> (1) qdev_prop_set_uint32(nvic, "num-irq", NUM_IRQ_LINES);
> (2) object_property_set_link(OBJECT(nvic), "memory",
> OBJECT(get_system_memory()), &error_abort);
> (3) sysbus_realize_and_unref(SYS_BUS_DEVICE(nvic), &error_fatal);
>
> static void armv7m_instance_init(Object *obj)
> {
> ...
> object_initialize_child(obj, "nvic", &s->nvic, TYPE_NVIC);
> object_property_add_alias(obj, "num-irq",
> OBJECT(&s->nvic), "num-irq");
>
> For (1) to set the "num-irq" property (aliased to TYPE_NVIC)
> before realization (3), it has to be available (aliased) first,
> thus has to be in the instance_init() handler.
>
> When the child creation depends on a property which is set by
> the parent, the property must be set before the realization,
> then is available in the realize() handler. For example with (2):
>
> static void armv7m_realize(DeviceState *dev, Error **errp)
> {
> ...
> if (!s->board_memory) {
> error_setg(errp, "memory property was not set");
> return;
> }
> memory_region_add_subregion_overlap(&s->container, 0,
> s->board_memory, -1);
>
> If your model only provides link/aliased properties, then it
> requires a instance_init() handler. If no property is consumed
> during realization, then to keep it simple you can avoid
> implementing a realize() handler, having all setup in instance_init().
>
> If your model only consumes properties (no link/alias), it must
> implement a realize() handler, and similarly you can skip the
> instance_init(), having all setup in realize().
>
> Now instance_init() is always called, and can never fail.
> The resources it allocates are freed later in instance_finalize().
>
> realize() can however fails and return error. If it succeeds,
> the resources are released in unrealize().
>
> If you have to implement realize() and it might fail, then it is
> cheaper to check the failing conditions first, then allocate
> resources. So in that case we prefer to avoid instance_init(),
> otherwise on failure we'd have allocated and released resources
> we know we'll not use. Pointless.
>
> Hope this is not too unclear and helps...
>
These are really helpful. Thanks a lot!
Do you think if we find a place in docs/develop to document such best
practice (qom.rst)?
> > For example, I see some devices put memory_region_init_io() and
> > sysbus_init_mmio() in their realize().
>
> Following my previous explanation, it is better (as cheaper) to
> have them in realize() indeed :)
>
Regards,
Bin