qemu-devel
[Top][All Lists]
Advanced

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

Re: [Qemu-devel] [PATCH v2 3/7] bcm2835_ic: add bcm2835 interrupt contro


From: Peter Crosthwaite
Subject: Re: [Qemu-devel] [PATCH v2 3/7] bcm2835_ic: add bcm2835 interrupt controller
Date: Wed, 30 Dec 2015 16:33:36 -0800

On Wed, Dec 23, 2015 at 4:25 PM, Andrew Baumann
<address@hidden> wrote:
> Signed-off-by: Andrew Baumann <address@hidden>
> ---
>
> Notes:
>     v2 changes:
>      * split inputs to named gpu_irq and arm_irq gpio inputs
>      * use 64-bit gpu_irq and 8-bit arm_irq status rather than 3*32-bit 
> bitfields
>      * added defined names for register offsets
>      * deleted nop realize method
>      * other misc cleanup suggested in review
>
>  hw/intc/Makefile.objs        |   1 +
>  hw/intc/bcm2835_ic.c         | 233 
> +++++++++++++++++++++++++++++++++++++++++++
>  include/hw/intc/bcm2835_ic.h |  33 ++++++
>  3 files changed, 267 insertions(+)
>  create mode 100644 hw/intc/bcm2835_ic.c
>  create mode 100644 include/hw/intc/bcm2835_ic.h
>
> diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
> index 004b0c2..2ad1204 100644
> --- a/hw/intc/Makefile.objs
> +++ b/hw/intc/Makefile.objs
> @@ -24,6 +24,7 @@ obj-$(CONFIG_GRLIB) += grlib_irqmp.o
>  obj-$(CONFIG_IOAPIC) += ioapic.o
>  obj-$(CONFIG_OMAP) += omap_intc.o
>  obj-$(CONFIG_OPENPIC_KVM) += openpic_kvm.o
> +obj-$(CONFIG_RASPI) += bcm2835_ic.o
>  obj-$(CONFIG_SH4) += sh_intc.o
>  obj-$(CONFIG_XICS) += xics.o
>  obj-$(CONFIG_XICS_KVM) += xics_kvm.o
> diff --git a/hw/intc/bcm2835_ic.c b/hw/intc/bcm2835_ic.c
> new file mode 100644
> index 0000000..9624e8b
> --- /dev/null
> +++ b/hw/intc/bcm2835_ic.c
> @@ -0,0 +1,233 @@
> +/*
> + * Raspberry Pi emulation (c) 2012 Gregory Estrade
> + * This code is licensed under the GNU GPLv2 and later.
> + * Heavily based on pl190.c, copyright terms below:
> + *
> + * Arm PrimeCell PL190 Vector Interrupt Controller
> + *
> + * Copyright (c) 2006 CodeSourcery.
> + * Written by Paul Brook
> + *

So your own modifications are now heavy enough for you and/or an
affiliation to claim at least co-authorship.

> + * This code is licensed under the GPL.
> + */
> +
> +#include "hw/intc/bcm2835_ic.h"
> +
> +#define GPU_IRQS 64
> +#define ARM_IRQS 8
> +
> +#define IRQ_PENDING_BASIC       0x00 /* IRQ basic pending */
> +#define IRQ_PENDING_1           0x04 /* IRQ pending 1 */
> +#define IRQ_PENDING_2           0x08 /* IRQ pending 2 */
> +#define FIQ_CONTROL             0x0C /* FIQ register */
> +#define IRQ_ENABLE_1            0x10 /* Interrupt enable register 1 */
> +#define IRQ_ENABLE_2            0x14 /* Interrupt enable register 2 */
> +#define IRQ_ENABLE_BASIC        0x18 /* Base interrupt enable register */
> +#define IRQ_DISABLE_1           0x1C /* Interrupt disable register 1 */
> +#define IRQ_DISABLE_2           0x20 /* Interrupt disable register 2 */
> +#define IRQ_DISABLE_BASIC       0x24 /* Base interrupt disable register */
> +
> +/* Update interrupts.  */
> +static void bcm2835_ic_update(BCM2835ICState *s)
> +{
> +    bool set = false;
> +
> +    if (s->fiq_enable) {
> +        if (s->fiq_select >= GPU_IRQS) {
> +            /* ARM IRQ */
> +            set = extract32(s->arm_irq_level, s->fiq_select - GPU_IRQS, 1);
> +        } else {
> +            set = extract64(s->gpu_irq_level, s->fiq_select, 1);
> +        }
> +    }
> +    qemu_set_irq(s->fiq, set);
> +
> +    set = (s->gpu_irq_level & s->gpu_irq_enable)
> +        || (s->arm_irq_level & s->arm_irq_enable);
> +    qemu_set_irq(s->irq, set);
> +
> +}
> +
> +static void bcm2835_ic_set_gpu_irq(void *opaque, int irq, int level)
> +{
> +    BCM2835ICState *s = opaque;

Blank line here.

> +    assert(irq >= 0 && irq < 64);
> +    s->gpu_irq_level = deposit64(s->gpu_irq_level, irq, 1, level != 0);
> +    bcm2835_ic_update(s);
> +}
> +
> +static void bcm2835_ic_set_arm_irq(void *opaque, int irq, int level)
> +{
> +    BCM2835ICState *s = opaque;

Blank line here.

> +    assert(irq >= 0 && irq < 8);
> +    s->arm_irq_level = deposit32(s->arm_irq_level, irq, 1, level != 0);
> +    bcm2835_ic_update(s);
> +}
> +
> +static const int irq_dups[] = { 7, 9, 10, 18, 19, 53, 54, 55, 56, 57, 62 };
> +
> +static uint64_t bcm2835_ic_read(void *opaque, hwaddr offset, unsigned size)
> +{
> +    BCM2835ICState *s = opaque;
> +    uint32_t res = 0;
> +    uint64_t gpu_pending = s->gpu_irq_level & s->gpu_irq_enable;
> +    int i;
> +
> +    switch (offset) {
> +    case IRQ_PENDING_BASIC:
> +        /* bits 0-7: ARM irqs */
> +        res = s->arm_irq_level & s->arm_irq_enable;
> +
> +        /* bits 8 & 9: pending registers 1 & 2 */
> +        res |= (((uint32_t)gpu_pending) != 0) << 8;
> +        res |= ((gpu_pending >> 32) != 0) << 9;
> +
> +        /* bits 10-20: selected GPU IRQs */
> +        for (i = 0; i < ARRAY_SIZE(irq_dups); i++) {
> +            res |= extract64(gpu_pending, irq_dups[i], 1) << (i + 10);
> +        }
> +        break;
> +    case IRQ_PENDING_1:  /* IRQ pending 1 */

Drop trailing comment here and all below.

> +        res = gpu_pending;
> +        break;
> +    case IRQ_PENDING_2:  /* IRQ pending 2 */
> +        res = gpu_pending >> 32;
> +        break;
> +    case FIQ_CONTROL:  /* FIQ register */
> +        res = (s->fiq_enable << 7) | s->fiq_select;
> +        break;
> +    case IRQ_ENABLE_1:  /* Interrupt enable register 1 */
> +        res = s->gpu_irq_enable;
> +        break;
> +    case IRQ_ENABLE_2:  /* Interrupt enable register 2 */
> +        res = s->gpu_irq_enable >> 32;
> +        break;
> +    case IRQ_ENABLE_BASIC:  /* Base interrupt enable register */
> +        res = s->arm_irq_enable;
> +        break;
> +    case IRQ_DISABLE_1:  /* Interrupt disable register 1 */
> +        res = ~s->gpu_irq_enable;
> +        break;
> +    case IRQ_DISABLE_2:  /* Interrupt disable register 2 */
> +        res = ~s->gpu_irq_enable >> 32;
> +        break;
> +    case IRQ_DISABLE_BASIC:  /* Base interrupt disable register */
> +        res = ~s->arm_irq_enable;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
> +                      __func__, offset);
> +        return 0;
> +    }
> +
> +    return res;
> +}
> +
> +static void bcm2835_ic_write(void *opaque, hwaddr offset, uint64_t val,
> +                             unsigned size)
> +{
> +    BCM2835ICState *s = opaque;
> +
> +    switch (offset) {
> +    case FIQ_CONTROL:
> +        s->fiq_select = (val & 0x7f);
> +        s->fiq_enable = (val >> 7) & 0x1;

extract32 for both (my criteria is if there is both a shift and mask
it should extract instead of be manual).

> +        break;
> +    case IRQ_ENABLE_1:
> +        s->gpu_irq_enable |= val;
> +        break;
> +    case IRQ_ENABLE_2:
> +        s->gpu_irq_enable |= val << 32;
> +        break;
> +    case IRQ_ENABLE_BASIC:
> +        s->arm_irq_enable |= val & 0xff;
> +        break;
> +    case IRQ_DISABLE_1:
> +        s->gpu_irq_enable &= ~val;
> +        break;
> +    case IRQ_DISABLE_2:
> +        s->gpu_irq_enable &= ~(val << 32);
> +        break;
> +    case IRQ_DISABLE_BASIC:
> +        s->arm_irq_enable &= ~val & 0xff;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR, "%s: Bad offset %"HWADDR_PRIx"\n",
> +                      __func__, offset);
> +        return;
> +    }
> +    bcm2835_ic_update(s);
> +}
> +
> +static const MemoryRegionOps bcm2835_ic_ops = {
> +    .read = bcm2835_ic_read,
> +    .write = bcm2835_ic_write,
> +    .endianness = DEVICE_NATIVE_ENDIAN,
> +    .valid.min_access_size = 4,
> +    .valid.max_access_size = 4,
> +};
> +
> +static void bcm2835_ic_reset(DeviceState *d)
> +{
> +    BCM2835ICState *s = BCM2835_IC(d);
> +
> +    s->gpu_irq_enable = 0;
> +    s->arm_irq_enable = 0;
> +    s->fiq_enable = false;
> +    s->fiq_select = 0;
> +}
> +
> +static void bcm2835_ic_init(Object *obj)
> +{
> +    BCM2835ICState *s = BCM2835_IC(obj);
> +
> +    memory_region_init_io(&s->iomem, obj, &bcm2835_ic_ops, s, 
> TYPE_BCM2835_IC,
> +                          0x200);
> +    sysbus_init_mmio(SYS_BUS_DEVICE(s), &s->iomem);
> +
> +    qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_gpu_irq,
> +                            BCM2835_IC_GPU_IRQ, GPU_IRQS);
> +    qdev_init_gpio_in_named(DEVICE(s), bcm2835_ic_set_arm_irq,
> +                            BCM2835_IC_ARM_IRQ, ARM_IRQS);
> +
> +    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->irq);
> +    sysbus_init_irq(SYS_BUS_DEVICE(s), &s->fiq);
> +}
> +
> +static const VMStateDescription vmstate_bcm2835_ic = {
> +    .name = TYPE_BCM2835_IC,
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]) {
> +        VMSTATE_UINT64(gpu_irq_level, BCM2835ICState),
> +        VMSTATE_UINT64(gpu_irq_enable, BCM2835ICState),
> +        VMSTATE_UINT8(arm_irq_level, BCM2835ICState),
> +        VMSTATE_UINT8(arm_irq_enable, BCM2835ICState),
> +        VMSTATE_BOOL(fiq_enable, BCM2835ICState),
> +        VMSTATE_UINT8(fiq_select, BCM2835ICState),
> +        VMSTATE_END_OF_LIST()
> +    }
> +};
> +
> +static void bcm2835_ic_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = bcm2835_ic_reset;
> +    dc->vmsd = &vmstate_bcm2835_ic;
> +}
> +
> +static TypeInfo bcm2835_ic_info = {
> +    .name          = TYPE_BCM2835_IC,
> +    .parent        = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(BCM2835ICState),
> +    .class_init    = bcm2835_ic_class_init,
> +    .instance_init = bcm2835_ic_init,
> +};
> +
> +static void bcm2835_ic_register_types(void)
> +{
> +    type_register_static(&bcm2835_ic_info);
> +}
> +
> +type_init(bcm2835_ic_register_types)
> diff --git a/include/hw/intc/bcm2835_ic.h b/include/hw/intc/bcm2835_ic.h
> new file mode 100644
> index 0000000..d897f44
> --- /dev/null
> +++ b/include/hw/intc/bcm2835_ic.h
> @@ -0,0 +1,33 @@
> +/*
> + * Raspberry Pi emulation (c) 2012 Gregory Estrade
> + * This code is licensed under the GNU GPLv2 and later.
> + */
> +
> +#ifndef BCM2835_IC_H
> +#define BCM2835_IC_H
> +
> +#include "hw/sysbus.h"
> +
> +#define TYPE_BCM2835_IC "bcm2835_ic"

s/_/-

> +#define BCM2835_IC(obj) OBJECT_CHECK(BCM2835ICState, (obj), TYPE_BCM2835_IC)
> +
> +#define BCM2835_IC_GPU_IRQ "gpu-irq"
> +#define BCM2835_IC_ARM_IRQ "arm-irq"
> +
> +typedef struct BCM2835ICState {
> +    /*< private >*/
> +    SysBusDevice busdev;
> +    /*< public >*/
> +
> +    MemoryRegion iomem;
> +
> +    /* 64 GPU IRQs + 8 ARM IRQs = 72 total (GPU first) */
> +    uint64_t gpu_irq_level, gpu_irq_enable;
> +    uint8_t arm_irq_level, arm_irq_enable;
> +    bool fiq_enable;
> +    uint8_t fiq_select;

> +    qemu_irq irq;
> +    qemu_irq fiq;

Move these two up to below iomem to separate IO from internal state.

Otherwise,

Reviewed-by: Peter Crosthwaite <address@hidden>

Regards,
Peter

> +} BCM2835ICState;
> +
> +#endif
> --
> 2.5.3
>



reply via email to

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