qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH 1/3] hw/intc/loongson_ipi_common: Add loongson ipi common cla


From: Jiaxun Yang
Subject: Re: [PATCH 1/3] hw/intc/loongson_ipi_common: Add loongson ipi common class
Date: Wed, 03 Jul 2024 14:16:34 +0800
User-agent: Cyrus-JMAP/3.11.0-alpha0-566-g3812ddbbc-fm-20240627.001-g3812ddbb


在2024年7月3日七月 上午10:12,Bibo Mao写道:
> Loongson ipi common class and instance is created here, it comes
> from file loongson_ipi mostly. For the new added loongson ipi
> common class, there is four interfaces defined here:
>  1. Interfaces pre_save/post_load are used for future kvm child class
>  2. Interface get_iocsr_as can be used for different architectures,
> now MIPS 3A4000 and LoongArch 3A5000 machine use this ip, can inherit
> this common class.

Please consider MMIO implementation here as well. Can you demonstrate
how would you share implementation with MMIO based IPI? In current
implementation we share memory R/W callbacks but in your implementation
that's nolonger possible.

If current implementation is hindering your future plan can you elaborate so we
can work on a resolution.

I'm happy to help with devlopment and testing.

>  3. Interace cpu_by_arch_id is added, by default generic function
> cpu_by_arch_id() is used to search vcpu from physical cpuid, it is
> generic searching method. Different machine may define another search
> method such binary searching method.

If you are going to implement some faster searching algorithm why don't we
 make it generic for all architectures?

Thanks
- Jiaxun

>
> Signed-off-by: Bibo Mao <maobibo@loongson.cn>
> ---
>  hw/intc/loongson_ipi_common.c         | 394 ++++++++++++++++++++++++++
>  include/hw/intc/loongson_ipi_common.h |  71 +++++
>  2 files changed, 465 insertions(+)
>  create mode 100644 hw/intc/loongson_ipi_common.c
>  create mode 100644 include/hw/intc/loongson_ipi_common.h
>
> diff --git a/hw/intc/loongson_ipi_common.c 
> b/hw/intc/loongson_ipi_common.c
> new file mode 100644
> index 0000000000..f462f24f32
> --- /dev/null
> +++ b/hw/intc/loongson_ipi_common.c
> @@ -0,0 +1,394 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Loongson ipi interrupt support
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#include "qemu/osdep.h"
> +#include "hw/boards.h"
> +#include "hw/sysbus.h"
> +#include "hw/intc/loongson_ipi_common.h"
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "qapi/error.h"
> +#include "qemu/log.h"
> +#include "exec/address-spaces.h"
> +#include "exec/memory.h"
> +#include "migration/vmstate.h"
> +#include "trace.h"
> +
> +static MemTxResult loongson_ipi_core_readl(void *opaque, hwaddr addr,
> +                                           uint64_t *data,
> +                                           unsigned size, MemTxAttrs 
> attrs)
> +{
> +    IPICore *s = opaque;
> +    uint64_t ret = 0;
> +    int index = 0;
> +
> +    addr &= 0xff;
> +    switch (addr) {
> +    case CORE_STATUS_OFF:
> +        ret = s->status;
> +        break;
> +    case CORE_EN_OFF:
> +        ret = s->en;
> +        break;
> +    case CORE_SET_OFF:
> +        ret = 0;
> +        break;
> +    case CORE_CLEAR_OFF:
> +        ret = 0;
> +        break;
> +    case CORE_BUF_20 ... CORE_BUF_38 + 4:
> +        index = (addr - CORE_BUF_20) >> 2;
> +        ret = s->buf[index];
> +        break;
> +    default:
> +        qemu_log_mask(LOG_UNIMP, "invalid read: %x", (uint32_t)addr);
> +        break;
> +    }
> +
> +    trace_loongson_ipi_read(size, (uint64_t)addr, ret);
> +    *data = ret;
> +    return MEMTX_OK;
> +}
> +
> +static MemTxResult loongson_ipi_iocsr_readl(void *opaque, hwaddr addr,
> +                                            uint64_t *data,
> +                                            unsigned size, MemTxAttrs 
> attrs)
> +{
> +    LoongsonIPICommonState *ipi = opaque;
> +    IPICore *s;
> +
> +    if (attrs.requester_id >= ipi->num_cpu) {
> +        return MEMTX_DECODE_ERROR;
> +    }
> +
> +    s = &ipi->cpu[attrs.requester_id];
> +    return loongson_ipi_core_readl(s, addr, data, size, attrs);
> +}
> +
> +static MemTxResult send_ipi_data(LoongsonIPICommonState *ipi, CPUState 
> *cpu,
> +                                 uint64_t val,
> +                                 hwaddr addr, MemTxAttrs attrs)
> +{
> +    int i, mask = 0, data = 0;
> +    AddressSpace *iocsr_as;
> +    LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
> +
> +    iocsr_as = NULL;
> +    if (licc->get_iocsr_as) {
> +        iocsr_as = licc->get_iocsr_as(cpu);
> +    }
> +
> +    if (!iocsr_as) {
> +        return MEMTX_DECODE_ERROR;
> +    }
> +
> +    /*
> +     * bit 27-30 is mask for byte writing,
> +     * if the mask is 0, we need not to do anything.
> +     */
> +    if ((val >> 27) & 0xf) {
> +        data = address_space_ldl_le(iocsr_as, addr, attrs, NULL);
> +        for (i = 0; i < 4; i++) {
> +            /* get mask for byte writing */
> +            if (val & (0x1 << (27 + i))) {
> +                mask |= 0xff << (i * 8);
> +            }
> +        }
> +    }
> +
> +    data &= mask;
> +    data |= (val >> 32) & ~mask;
> +    address_space_stl_le(iocsr_as, addr, data, attrs, NULL);
> +
> +    return MEMTX_OK;
> +}
> +
> +static CPUState *get_cpu_by_arch_id(LoongsonIPICommonState *ipi, 
> uint32_t cpuid)
> +{
> +    LoongsonIPICommonClass *licc = LOONGSON_IPI_COMMON_GET_CLASS(ipi);
> +
> +    if (licc->cpu_by_arch_id) {
> +        return licc->cpu_by_arch_id(cpuid);
> +    }
> +
> +    return cpu_by_arch_id(cpuid);
> +}
> +
> +static MemTxResult mail_send(LoongsonIPICommonState *ipi, uint64_t val,
> +                             MemTxAttrs attrs)
> +{
> +    uint32_t cpuid;
> +    hwaddr addr;
> +    CPUState *cs;
> +
> +    cpuid = extract32(val, 16, 10);
> +    cs = get_cpu_by_arch_id(ipi, cpuid);
> +    if (cs == NULL) {
> +        return MEMTX_DECODE_ERROR;
> +    }
> +
> +    /* override requester_id */
> +    addr = SMP_IPI_MAILBOX + CORE_BUF_20 + (val & 0x1c);
> +    attrs.requester_id = cs->cpu_index;
> +    return send_ipi_data(ipi, cs, val, addr, attrs);
> +}
> +
> +static MemTxResult any_send(LoongsonIPICommonState *ipi, uint64_t val,
> +                            MemTxAttrs attrs)
> +{
> +    uint32_t cpuid;
> +    hwaddr addr;
> +    CPUState *cs;
> +
> +    cpuid = extract32(val, 16, 10);
> +    cs = get_cpu_by_arch_id(ipi, cpuid);
> +    if (cs == NULL) {
> +        return MEMTX_DECODE_ERROR;
> +    }
> +
> +    /* override requester_id */
> +    addr = val & 0xffff;
> +    attrs.requester_id = cs->cpu_index;
> +    return send_ipi_data(ipi, cs, val, addr, attrs);
> +}
> +
> +static MemTxResult loongson_ipi_core_writel(void *opaque, hwaddr addr,
> +                                            uint64_t val, unsigned 
> size,
> +                                            MemTxAttrs attrs)
> +{
> +    IPICore *s = opaque;
> +    LoongsonIPICommonState *ipi = s->ipi;
> +    int index = 0;
> +    uint32_t cpuid;
> +    uint8_t vector;
> +    CPUState *cs;
> +
> +    addr &= 0xff;
> +    trace_loongson_ipi_write(size, (uint64_t)addr, val);
> +    switch (addr) {
> +    case CORE_STATUS_OFF:
> +        qemu_log_mask(LOG_GUEST_ERROR, "can not be written");
> +        break;
> +    case CORE_EN_OFF:
> +        s->en = val;
> +        break;
> +    case CORE_SET_OFF:
> +        s->status |= val;
> +        if (s->status != 0 && (s->status & s->en) != 0) {
> +            qemu_irq_raise(s->irq);
> +        }
> +        break;
> +    case CORE_CLEAR_OFF:
> +        s->status &= ~val;
> +        if (s->status == 0 && s->en != 0) {
> +            qemu_irq_lower(s->irq);
> +        }
> +        break;
> +    case CORE_BUF_20 ... CORE_BUF_38 + 4:
> +        index = (addr - CORE_BUF_20) >> 2;
> +        s->buf[index] = val;
> +        break;
> +    case IOCSR_IPI_SEND:
> +        cpuid = extract32(val, 16, 10);
> +        /* IPI status vector */
> +        vector = extract8(val, 0, 5);
> +        cs = get_cpu_by_arch_id(ipi, cpuid);
> +        if (cs == NULL || cs->cpu_index >= ipi->num_cpu) {
> +            return MEMTX_DECODE_ERROR;
> +        }
> +        loongson_ipi_core_writel(&ipi->cpu[cs->cpu_index], 
> CORE_SET_OFF,
> +                                 BIT(vector), 4, attrs);
> +        break;
> +    default:
> +        qemu_log_mask(LOG_UNIMP, "invalid write: %x", (uint32_t)addr);
> +        break;
> +    }
> +
> +    return MEMTX_OK;
> +}
> +
> +static MemTxResult loongson_ipi_iocsr_writel(void *opaque, hwaddr addr,
> +                                            uint64_t val, unsigned 
> size,
> +                                            MemTxAttrs attrs)
> +{
> +    LoongsonIPICommonState *ipi = opaque;
> +    IPICore *s;
> +
> +    if (attrs.requester_id >= ipi->num_cpu) {
> +        return MEMTX_DECODE_ERROR;
> +    }
> +
> +    s = &ipi->cpu[attrs.requester_id];
> +    return loongson_ipi_core_writel(s, addr, val, size, attrs);
> +}
> +
> +static const MemoryRegionOps loongson_ipi_iocsr_ops = {
> +    .read_with_attrs = loongson_ipi_iocsr_readl,
> +    .write_with_attrs = loongson_ipi_iocsr_writel,
> +    .impl.min_access_size = 4,
> +    .impl.max_access_size = 4,
> +    .valid.min_access_size = 4,
> +    .valid.max_access_size = 8,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +/* mail send and any send only support writeq */
> +static MemTxResult loongson_ipi_writeq(void *opaque, hwaddr addr, 
> uint64_t val,
> +                                        unsigned size, MemTxAttrs 
> attrs)
> +{
> +    MemTxResult ret = MEMTX_OK;
> +    LoongsonIPICommonState *ipi = opaque;
> +
> +    addr &= 0xfff;
> +    switch (addr) {
> +    case MAIL_SEND_OFFSET:
> +        ret = mail_send(ipi, val, attrs);
> +        break;
> +    case ANY_SEND_OFFSET:
> +        ret = any_send(ipi, val, attrs);
> +        break;
> +    default:
> +       break;
> +    }
> +
> +    return ret;
> +}
> +
> +static const MemoryRegionOps loongson_ipi64_ops = {
> +    .write_with_attrs = loongson_ipi_writeq,
> +    .impl.min_access_size = 8,
> +    .impl.max_access_size = 8,
> +    .valid.min_access_size = 8,
> +    .valid.max_access_size = 8,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +};
> +
> +static void loongson_ipi_common_realize(DeviceState *dev, Error **errp)
> +{
> +    LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(dev);
> +    SysBusDevice *sbd = SYS_BUS_DEVICE(dev);
> +    int i;
> +
> +    if (s->num_cpu == 0) {
> +        error_setg(errp, "num-cpu must be at least 1");
> +        return;
> +    }
> +
> +    memory_region_init_io(&s->ipi_iocsr_mem, OBJECT(dev),
> +                          &loongson_ipi_iocsr_ops,
> +                          s, "loongson_ipi_iocsr", 0x48);
> +
> +    /* loongson_ipi_iocsr performs re-entrant IO through ipi_send */
> +    s->ipi_iocsr_mem.disable_reentrancy_guard = true;
> +
> +    sysbus_init_mmio(sbd, &s->ipi_iocsr_mem);
> +
> +    memory_region_init_io(&s->ipi64_iocsr_mem, OBJECT(dev),
> +                          &loongson_ipi64_ops,
> +                          s, "loongson_ipi64_iocsr", 0x118);
> +    sysbus_init_mmio(sbd, &s->ipi64_iocsr_mem);
> +
> +    s->cpu = g_new0(IPICore, s->num_cpu);
> +    if (s->cpu == NULL) {
> +        error_setg(errp, "Memory allocation for IPICore faile");
> +        return;
> +    }
> +
> +    for (i = 0; i < s->num_cpu; i++) {
> +        s->cpu[i].ipi = s;
> +        qdev_init_gpio_out(dev, &s->cpu[i].irq, 1);
> +    }
> +}
> +
> +static int loongson_ipi_pre_save(void *opaque)
> +{
> +    LoongsonIPICommonState *s = (LoongsonIPICommonState *)opaque;
> +    LoongsonIPICommonClass *c = LOONGSON_IPI_COMMON_GET_CLASS(s);
> +
> +    if (c->pre_save) {
> +        c->pre_save(s);
> +    }
> +
> +    return 0;
> +}
> +
> +static int loongson_ipi_post_load(void *opaque, int version_id)
> +{
> +    LoongsonIPICommonState *s = (LoongsonIPICommonState *)opaque;
> +    LoongsonIPICommonClass *c = LOONGSON_IPI_COMMON_GET_CLASS(s);
> +
> +    if (c->post_load) {
> +        c->post_load(s);
> +    }
> +    return 0;
> +}
> +
> +static const VMStateDescription vmstate_ipi_core = {
> +    .name = "ipi-single",
> +    .version_id = 2,
> +    .minimum_version_id = 2,
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_UINT32(status, IPICore),
> +        VMSTATE_UINT32(en, IPICore),
> +        VMSTATE_UINT32(set, IPICore),
> +        VMSTATE_UINT32(clear, IPICore),
> +        VMSTATE_UINT32_ARRAY(buf, IPICore, IPI_MBX_NUM * 2),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static const VMStateDescription vmstate_loongson_ipi = {
> +    /* Fixed name to keep compatible */
> +    .name = "loongson_ipi",
> +    .pre_save  = loongson_ipi_pre_save,
> +    .post_load = loongson_ipi_post_load,
> +    .version_id = 2,
> +    .minimum_version_id = 2,
> +    .fields = (const VMStateField[]) {
> +        VMSTATE_STRUCT_VARRAY_POINTER_UINT32(cpu, 
> LoongsonIPICommonState,
> +                                       num_cpu, vmstate_ipi_core, 
> IPICore),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static Property ipi_properties[] = {
> +    DEFINE_PROP_UINT32("num-cpu", LoongsonIPICommonState, num_cpu, 1),
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +static void loongson_ipi_common_class_init(ObjectClass *klass, void 
> *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->realize = loongson_ipi_common_realize;
> +    device_class_set_props(dc, ipi_properties);
> +    dc->vmsd = &vmstate_loongson_ipi;
> +}
> +
> +static void loongson_ipi_common_finalize(Object *obj)
> +{
> +    LoongsonIPICommonState *s = LOONGSON_IPI_COMMON(obj);
> +
> +    g_free(s->cpu);
> +}
> +
> +static const TypeInfo loongson_ipi_common_info = {
> +    .name          = TYPE_LOONGSON_IPI_COMMON,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(LoongsonIPICommonState),
> +    .class_size    = sizeof(LoongsonIPICommonClass),
> +    .class_init    = loongson_ipi_common_class_init,
> +    .instance_finalize = loongson_ipi_common_finalize,
> +    .abstract = true,
> +};
> +
> +static void loongson_ipi_common_register_types(void)
> +{
> +    type_register_static(&loongson_ipi_common_info);
> +}
> +
> +type_init(loongson_ipi_common_register_types)
> diff --git a/include/hw/intc/loongson_ipi_common.h 
> b/include/hw/intc/loongson_ipi_common.h
> new file mode 100644
> index 0000000000..1f074863e6
> --- /dev/null
> +++ b/include/hw/intc/loongson_ipi_common.h
> @@ -0,0 +1,71 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later */
> +/*
> + * Loongson ipi interrupt header files
> + *
> + * Copyright (C) 2021 Loongson Technology Corporation Limited
> + */
> +
> +#ifndef HW_LOONGSON_IPI_COMMON_H
> +#define HW_LOONGSON_IPI_COMMON_H
> +
> +#include "hw/sysbus.h"
> +#include "hw/core/cpu.h"
> +#include "qom/object.h"
> +
> +/* Mainy used by iocsr read and write */
> +#define SMP_IPI_MAILBOX      0x1000ULL
> +#define CORE_STATUS_OFF       0x0
> +#define CORE_EN_OFF           0x4
> +#define CORE_SET_OFF          0x8
> +#define CORE_CLEAR_OFF        0xc
> +#define CORE_BUF_20           0x20
> +#define CORE_BUF_28           0x28
> +#define CORE_BUF_30           0x30
> +#define CORE_BUF_38           0x38
> +#define IOCSR_IPI_SEND        0x40
> +#define IOCSR_MAIL_SEND       0x48
> +#define IOCSR_ANY_SEND        0x158
> +
> +#define MAIL_SEND_ADDR        (SMP_IPI_MAILBOX + IOCSR_MAIL_SEND)
> +#define MAIL_SEND_OFFSET      0
> +#define ANY_SEND_OFFSET       (IOCSR_ANY_SEND - IOCSR_MAIL_SEND)
> +
> +#define IPI_MBX_NUM           4
> +
> +#define TYPE_LOONGSON_IPI_COMMON "loongson_ipi_common"
> +typedef struct LoongsonIPICommonClass LoongsonIPICommonClass;
> +typedef struct LoongsonIPICommonState LoongsonIPICommonState;
> +DECLARE_OBJ_CHECKERS(LoongsonIPICommonState, LoongsonIPICommonClass,
> +                     LOONGSON_IPI_COMMON, TYPE_LOONGSON_IPI_COMMON)
> +
> +typedef struct IPICore {
> +    LoongsonIPICommonState *ipi;
> +    uint32_t status;
> +    uint32_t en;
> +    uint32_t set;
> +    uint32_t clear;
> +    /* 64bit buf divide into 2 32bit buf */
> +    uint32_t buf[IPI_MBX_NUM * 2];
> +    qemu_irq irq;
> +} IPICore;
> +
> +struct LoongsonIPICommonState {
> +    SysBusDevice parent_obj;
> +    MemoryRegion ipi_iocsr_mem;
> +    MemoryRegion ipi64_iocsr_mem;
> +    uint32_t num_cpu;
> +    IPICore *cpu;
> +};
> +
> +struct LoongsonIPICommonClass {
> +    /*< private >*/
> +    SysBusDeviceClass parent_class;
> +    /*< public >*/
> +
> +    void (*pre_save)(LoongsonIPICommonState *s);
> +    void (*post_load)(LoongsonIPICommonState *s);
> +    AddressSpace *(*get_iocsr_as)(CPUState *cpu);
> +    CPUState *(*cpu_by_arch_id)(int64_t id);
> +};
> +
> +#endif
> -- 
> 2.39.3

-- 
- Jiaxun



reply via email to

[Prev in Thread] Current Thread [Next in Thread]