diff mbox

[v7,5/8] irq: Add a new irq device that allows the ORing of lines

Message ID 251a4110c1289188a85031324fbe9b1db7aedbd5.1473579576.git.alistair@alistair23.me (mailing list archive)
State New, archived
Headers show

Commit Message

Alistair Francis Sept. 11, 2016, 2:54 p.m. UTC
Signed-off-by: Alistair Francis <alistair@alistair23.me>
---
As the migration framework is not included in user mode this needs to be a
new file.

V7:
 - Use the standard QEMU init/realise functions
V6:
 - Make the OR IRQ device a TYPE_DEVICE
 - Add vmstate

 hw/core/Makefile.objs |   1 +
 hw/core/or-irq.c      | 117 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/hw/or-irq.h   |  46 ++++++++++++++++++++
 3 files changed, 164 insertions(+)
 create mode 100644 hw/core/or-irq.c
 create mode 100644 include/hw/or-irq.h

Comments

Peter Maydell Sept. 19, 2016, 2:03 p.m. UTC | #1
On 11 September 2016 at 15:54, Alistair Francis <alistair23@gmail.com> wrote:
> Signed-off-by: Alistair Francis <alistair@alistair23.me>
> ---
> As the migration framework is not included in user mode this needs to be a
> new file.
>
> V7:
>  - Use the standard QEMU init/realise functions
> V6:
>  - Make the OR IRQ device a TYPE_DEVICE
>  - Add vmstate
> +static void or_irq_handler(void *opaque, int n, int level)
> +{
> +    qemu_or_irq *s = OR_IRQ(opaque);
> +    int or_level = 0;
> +    int i;
> +
> +    s->levels[n] = level;
> +
> +    for (i = 0; i < s->num_lines; i++) {
> +        or_level |= s->levels[i];
> +    }
> +
> +    qemu_set_irq(s->out_irq, or_level);
> +}
> +
> +static void or_irq_reset(DeviceState *dev)
> +{
> +    qemu_or_irq *s = OR_IRQ(dev);
> +    int i;
> +
> +    for (i = 0; i < MAX_OR_LINES; i++) {
> +        s->levels[i] = false;
> +    }
> +
> +    /* Trigger an update of the out irqs. We just set the level to 0 */
> +    or_irq_handler(s, 0, 0);

Changing an output qdev IRQ line on reset() is generally
not recommended. Is it necessary here?

> +#include "hw/irq.h"
> +#include "hw/sysbus.h"
> +#include "qom/object.h"
> +
> +#define TYPE_OR_IRQ "or-irq"
> +
> +#define MAX_OR_LINES      16

This is a slightly arbitrary limit, but it's bigger than anybody's
really likely to need and there's a forward compatible path for
migration if we need to support larger sizes in future, so it's OK.
(if num_lines > 16 you would dynamically allocate a levels array
and migrate it with a migration subsection that's only present if the
num_lines property is >16)

> +typedef struct OrIRQState qemu_or_irq;
> +
> +#define OR_IRQ(obj) OBJECT_CHECK(qemu_or_irq, (obj), TYPE_OR_IRQ)
> +
> +struct OrIRQState {
> +    DeviceState parent_obj;
> +
> +    qemu_irq out_irq;
> +    qemu_irq *in_irqs;
> +    bool levels[MAX_OR_LINES];
> +    uint16_t num_lines;
> +};
> +
> +qemu_irq *qemu_get_or_irqs(DeviceState *dev);

Why this rather than defining the input lines with qdev_init_gpio_in()
so the users can use qdev_get_gpio_in() ?

thanks
-- PMM
Alistair Francis Sept. 24, 2016, 5:21 p.m. UTC | #2
On Mon, Sep 19, 2016 at 7:03 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 11 September 2016 at 15:54, Alistair Francis <alistair23@gmail.com> wrote:
>> Signed-off-by: Alistair Francis <alistair@alistair23.me>
>> ---
>> As the migration framework is not included in user mode this needs to be a
>> new file.
>>
>> V7:
>>  - Use the standard QEMU init/realise functions
>> V6:
>>  - Make the OR IRQ device a TYPE_DEVICE
>>  - Add vmstate
>> +static void or_irq_handler(void *opaque, int n, int level)
>> +{
>> +    qemu_or_irq *s = OR_IRQ(opaque);
>> +    int or_level = 0;
>> +    int i;
>> +
>> +    s->levels[n] = level;
>> +
>> +    for (i = 0; i < s->num_lines; i++) {
>> +        or_level |= s->levels[i];
>> +    }
>> +
>> +    qemu_set_irq(s->out_irq, or_level);
>> +}
>> +
>> +static void or_irq_reset(DeviceState *dev)
>> +{
>> +    qemu_or_irq *s = OR_IRQ(dev);
>> +    int i;
>> +
>> +    for (i = 0; i < MAX_OR_LINES; i++) {
>> +        s->levels[i] = false;
>> +    }
>> +
>> +    /* Trigger an update of the out irqs. We just set the level to 0 */
>> +    or_irq_handler(s, 0, 0);
>
> Changing an output qdev IRQ line on reset() is generally
> not recommended. Is it necessary here?

No, it isn't necessary. I have removed it.

>
>> +#include "hw/irq.h"
>> +#include "hw/sysbus.h"
>> +#include "qom/object.h"
>> +
>> +#define TYPE_OR_IRQ "or-irq"
>> +
>> +#define MAX_OR_LINES      16
>
> This is a slightly arbitrary limit, but it's bigger than anybody's
> really likely to need and there's a forward compatible path for
> migration if we need to support larger sizes in future, so it's OK.
> (if num_lines > 16 you would dynamically allocate a levels array
> and migrate it with a migration subsection that's only present if the
> num_lines property is >16)
>
>> +typedef struct OrIRQState qemu_or_irq;
>> +
>> +#define OR_IRQ(obj) OBJECT_CHECK(qemu_or_irq, (obj), TYPE_OR_IRQ)
>> +
>> +struct OrIRQState {
>> +    DeviceState parent_obj;
>> +
>> +    qemu_irq out_irq;
>> +    qemu_irq *in_irqs;
>> +    bool levels[MAX_OR_LINES];
>> +    uint16_t num_lines;
>> +};
>> +
>> +qemu_irq *qemu_get_or_irqs(DeviceState *dev);
>
> Why this rather than defining the input lines with qdev_init_gpio_in()
> so the users can use qdev_get_gpio_in() ?

I was worried that I couldn't create the interrupts in the realise
function, but it seems to work.

Thanks,

Alistair

>
> thanks
> -- PMM
diff mbox

Patch

diff --git a/hw/core/Makefile.objs b/hw/core/Makefile.objs
index cfd4840..b47241b 100644
--- a/hw/core/Makefile.objs
+++ b/hw/core/Makefile.objs
@@ -16,4 +16,5 @@  common-obj-$(CONFIG_SOFTMMU) += null-machine.o
 common-obj-$(CONFIG_SOFTMMU) += loader.o
 common-obj-$(CONFIG_SOFTMMU) += qdev-properties-system.o
 common-obj-$(CONFIG_SOFTMMU) += register.o
+common-obj-$(CONFIG_SOFTMMU) += or-irq.o
 common-obj-$(CONFIG_PLATFORM_BUS) += platform-bus.o
diff --git a/hw/core/or-irq.c b/hw/core/or-irq.c
new file mode 100644
index 0000000..840b1b6
--- /dev/null
+++ b/hw/core/or-irq.c
@@ -0,0 +1,117 @@ 
+/*
+ * QEMU IRQ/GPIO common code.
+ *
+ * Copyright (c) 2016 Alistair Francis <alistair@alistair23.me>.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+#include "hw/or-irq.h"
+
+qemu_irq *qemu_get_or_irqs(DeviceState *dev)
+{
+    qemu_or_irq *s = OR_IRQ(dev);
+
+    return s->in_irqs;
+}
+
+static void or_irq_handler(void *opaque, int n, int level)
+{
+    qemu_or_irq *s = OR_IRQ(opaque);
+    int or_level = 0;
+    int i;
+
+    s->levels[n] = level;
+
+    for (i = 0; i < s->num_lines; i++) {
+        or_level |= s->levels[i];
+    }
+
+    qemu_set_irq(s->out_irq, or_level);
+}
+
+static void or_irq_reset(DeviceState *dev)
+{
+    qemu_or_irq *s = OR_IRQ(dev);
+    int i;
+
+    for (i = 0; i < MAX_OR_LINES; i++) {
+        s->levels[i] = false;
+    }
+
+    /* Trigger an update of the out irqs. We just set the level to 0 */
+    or_irq_handler(s, 0, 0);
+}
+
+static void or_irq_realize(DeviceState *dev, Error **errp)
+{
+    qemu_or_irq *s = OR_IRQ(dev);
+
+    assert(s->num_lines < MAX_OR_LINES);
+
+    s->in_irqs = qemu_allocate_irqs(or_irq_handler, s, s->num_lines);
+}
+
+static void or_irq_init(Object *obj)
+{
+    qemu_or_irq *s = OR_IRQ(obj);
+
+    qdev_init_gpio_out(DEVICE(obj), &s->out_irq, 1);
+}
+
+static const VMStateDescription vmstate_or_irq = {
+    .name = TYPE_OR_IRQ,
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]) {
+        VMSTATE_BOOL_ARRAY(levels, qemu_or_irq, MAX_OR_LINES),
+        VMSTATE_END_OF_LIST(),
+    }
+};
+
+static Property or_irq_properties[] = {
+    DEFINE_PROP_UINT16("num-lines", qemu_or_irq, num_lines, 1),
+    DEFINE_PROP_END_OF_LIST(),
+};
+
+static void or_irq_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = or_irq_reset;
+    dc->props = or_irq_properties;
+    dc->realize = or_irq_realize;
+    dc->vmsd = &vmstate_or_irq;
+}
+
+static const TypeInfo or_irq_type_info = {
+   .name = TYPE_OR_IRQ,
+   .parent = TYPE_DEVICE,
+   .instance_size = sizeof(qemu_or_irq),
+   .instance_init = or_irq_init,
+   .class_init = or_irq_class_init,
+};
+
+static void or_irq_register_types(void)
+{
+    type_register_static(&or_irq_type_info);
+}
+
+type_init(or_irq_register_types)
diff --git a/include/hw/or-irq.h b/include/hw/or-irq.h
new file mode 100644
index 0000000..19455ee
--- /dev/null
+++ b/include/hw/or-irq.h
@@ -0,0 +1,46 @@ 
+/*
+ * QEMU IRQ/GPIO common code.
+ *
+ * Copyright (c) 2016 Alistair Francis <alistair@alistair23.me>.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "hw/irq.h"
+#include "hw/sysbus.h"
+#include "qom/object.h"
+
+#define TYPE_OR_IRQ "or-irq"
+
+#define MAX_OR_LINES      16
+
+typedef struct OrIRQState qemu_or_irq;
+
+#define OR_IRQ(obj) OBJECT_CHECK(qemu_or_irq, (obj), TYPE_OR_IRQ)
+
+struct OrIRQState {
+    DeviceState parent_obj;
+
+    qemu_irq out_irq;
+    qemu_irq *in_irqs;
+    bool levels[MAX_OR_LINES];
+    uint16_t num_lines;
+};
+
+qemu_irq *qemu_get_or_irqs(DeviceState *dev);