diff mbox

[RFC,V5,6/9] hw/intc: arm_gicv3_spi_its

Message ID 1445361732-16257-7-git-send-email-shlomopongratz@gmail.com
State New
Headers show

Commit Message

Shlomo Pongratz Oct. 20, 2015, 5:22 p.m. UTC
From: Shlomo Pongratz <shlomo.pongratz@huawei.com>

This patch includes a placeholder code for future spi and its
implementation.

Signed-off-by: Shlomo Pongratz <shlomo.pongratz@huawei.com>
---
 hw/intc/Makefile.objs       |   1 +
 hw/intc/arm_gicv3_spi_its.c | 359 ++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/arm_gicv3_spi_its.h |  11 ++
 3 files changed, 371 insertions(+)
 create mode 100644 hw/intc/arm_gicv3_spi_its.c
 create mode 100644 hw/intc/arm_gicv3_spi_its.h

Comments

Pavel Fedin Oct. 21, 2015, 12:43 p.m. UTC | #1
Hello!

> This patch includes a placeholder code for future spi and its
> implementation.

 Forgot to comment on this. I see that here you are building an ITS into GIC as a monolithic thing. This can be wrong because we
could want to emulate platforms which have GICv3 but don't have ITS. I would suggest to implement ITS as a separate class, and i
have actually done it in http://lists.nongnu.org/archive/html/qemu-devel/2015-10/msg04613.html.
 So, i think we should not bother about ITS for now and suggest you to leave it out completely and focus on pure GICv3.
 Even more, i have software-emulated ITS code in one of my abandoned branches, it lacks only GICv3's ability to receive LPIs (which
is indeed GIC's functionality). After you're done with GIC, i could rebase it on top and post at least as an RFC. May be i'll
complete it myself, may be you'll want to pick it up, i don't know. Actually, it works with Linux kernel and successfully translates
an MSI event into LPI number, which is then injected into the GIC object. Just it's GIC missing the appropriate LPI hanlders. I
wrote it when there was no in-kernel vITS implementation, but abandoned when vITS patch series was published.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Shlomo Pongratz Oct. 21, 2015, 1:05 p.m. UTC | #2
Hi,

I just added a placeholder, I didn't add any functionality.

On Wednesday, October 21, 2015, Pavel Fedin <p.fedin@samsung.com> wrote:

>  Hello!
>
> > This patch includes a placeholder code for future spi and its
> > implementation.
>
>  Forgot to comment on this. I see that here you are building an ITS into
> GIC as a monolithic thing. This can be wrong because we
> could want to emulate platforms which have GICv3 but don't have ITS. I
> would suggest to implement ITS as a separate class, and i
> have actually done it in
> http://lists.nongnu.org/archive/html/qemu-devel/2015-10/msg04613.html.
>  So, i think we should not bother about ITS for now and suggest you to
> leave it out completely and focus on pure GICv3.
>  Even more, i have software-emulated ITS code in one of my abandoned
> branches, it lacks only GICv3's ability to receive LPIs (which
> is indeed GIC's functionality). After you're done with GIC, i could rebase
> it on top and post at least as an RFC. May be i'll
> complete it myself, may be you'll want to pick it up, i don't know.
> Actually, it works with Linux kernel and successfully translates
> an MSI event into LPI number, which is then injected into the GIC object.
> Just it's GIC missing the appropriate LPI hanlders. I
> wrote it when there was no in-kernel vITS implementation, but abandoned
> when vITS patch series was published.
>
> Kind regards,
> Pavel Fedin
> Expert Engineer
> Samsung Electronics Research center Russia
>
>
>
Pavel Fedin Oct. 21, 2015, 1:12 p.m. UTC | #3
Hello!

> I just added a placeholder, I didn't add any functionality.

 I see. Just wanted to say, that if we accept my proposal (implementing ITS as a separate object), then the only thing we would do with this placeholder is to remove it. It should go then to something like hw/intc/arm_gicv3_its.c and its object should inherit from TYPE_ARM_GICV3_ITS_COMMON.
 Or do you have some explicit reasons to have everything as a monolith?

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Shlomo Pongratz Oct. 21, 2015, 1:14 p.m. UTC | #4
On Wednesday, October 21, 2015, Pavel Fedin <p.fedin@samsung.com> wrote:

>  Hello!
>
> > I just added a placeholder, I didn't add any functionality.
>
>  I see. Just wanted to say, that if we accept my proposal (implementing
> ITS as a separate object), then the only thing we would do with this
> placeholder is to remove it. It should go then to something like
> hw/intc/arm_gicv3_its.c and its object should inherit from
> TYPE_ARM_GICV3_ITS_COMMON.
>  Or do you have some explicit reasons to have everything as a monolith?
>

No I just didn't want to have 3 stub files spi, its and its_control.
Do you suggest that I'll split it to 3 files?

>
> Kind regards,
> Pavel Fedin
> Expert Engineer
> Samsung Electronics Research center Russia
>
>
>
Pavel Fedin Oct. 21, 2015, 1:48 p.m. UTC | #5
Hello!

>> Or do you have some explicit reasons to have everything as a monolith?
> No I just didn't want to have 3 stub files spi, its and its_control.
> Do you suggest that I'll split it to 3 files?

 You didn't understand my question. It's not about internal structure of ITS implementation. It is about GIC and ITS connection.
 Please review my KVM ITS RFC: http://lists.nongnu.org/archive/html/qemu-devel/2015-10/msg04613.html. You'll see that ITS is a separate object of a separate class, which can even be omitted at all, if machine model doesn't need it for some reason. So, i suggest that all the ITS code should go there, and it would be a completely separate entity, and a separate patch set, after your GICv3 is accepted. I will help you with this.
 Peter, i know you can be very busy, but, could you at least take a glance at my vITS v2 RFC structure and judge us? Should ITS + GICv3 be a monolithic object, or is my suggestion better?
 By the way, gicv3_init_irqs_and_mmio() expects only two regions, so it will not even pay attention to your stubs. You could patch it, of course, but... I don't think it's the good thing to do.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Shlomo Pongratz Oct. 21, 2015, 2:19 p.m. UTC | #6
Hi,

As far as I understand Figure 1 in GICv3 architecture document the
interrupts from device goes to the distributor and from it to the
re-distributors or from the deices via the ITS to the re-distributors.
So eventually ITS should be part of the GIC. That is if the ITS is a
different entity how do you see it work with the rest of the GIC?


On Wednesday, October 21, 2015, Pavel Fedin <p.fedin@samsung.com> wrote:

>  Hello!
>
> >> Or do you have some explicit reasons to have everything as a monolith?
> > No I just didn't want to have 3 stub files spi, its and its_control.
> > Do you suggest that I'll split it to 3 files?
>
>  You didn't understand my question. It's not about internal structure of
> ITS implementation. It is about GIC and ITS connection.
>  Please review my KVM ITS RFC:
> http://lists.nongnu.org/archive/html/qemu-devel/2015-10/msg04613.html.
> You'll see that ITS is a separate object of a separate class, which can
> even be omitted at all, if machine model doesn't need it for some reason.
> So, i suggest that all the ITS code should go there, and it would be a
> completely separate entity, and a separate patch set, after your GICv3 is
> accepted. I will help you with this.
>  Peter, i know you can be very busy, but, could you at least take a glance
> at my vITS v2 RFC structure and judge us? Should ITS + GICv3 be a
> monolithic object, or is my suggestion better?
>  By the way, gicv3_init_irqs_and_mmio() expects only two regions, so it
> will not even pay attention to your stubs. You could patch it, of course,
> but... I don't think it's the good thing to do.
>
> Kind regards,
> Pavel Fedin
> Expert Engineer
> Samsung Electronics Research center Russia
>
>
>
Pavel Fedin Oct. 21, 2015, 2:26 p.m. UTC | #7
Hello!

> As far as I understand Figure 1 in GICv3 architecture document the interrupts from device goes to the distributor and from it to the
> re-distributors or from the deices via the ITS to the re-distributors.
> So eventually ITS should be part of the GIC. That is if the ITS is a different entity how do you see it work with the rest of the GIC?

 Easy. As i said before, what ITS actually does is transforming device ID + event ID into a single LPI number. Then, an LPI goes to the redistributor. Therefore, all we need from GIC is a method like inject_lpi(int lpi). Well, may be a couple more, for moving LPIs between collections. But this is not a problem and makes up a nice interface.
 Even on the picture you mentioned ITS is a kind of separate thing. It can even be completely missing.

 Well, my reasons end here. If you still disagree... Do what you want then, it will not be a problem to remove these unused stubs.
 Peter, we are summoning you. :)

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Shlomo Pongratz Oct. 21, 2015, 2:35 p.m. UTC | #8
I just wanted to understand. I don't have any preferences.

On Wednesday, October 21, 2015, Pavel Fedin <p.fedin@samsung.com> wrote:

>  Hello!
>
> > As far as I understand Figure 1 in GICv3 architecture document the
> interrupts from device goes to the distributor and from it to the
> > re-distributors or from the deices via the ITS to the re-distributors.
> > So eventually ITS should be part of the GIC. That is if the ITS is a
> different entity how do you see it work with the rest of the GIC?
>
>  Easy. As i said before, what ITS actually does is transforming device ID
> + event ID into a single LPI number. Then, an LPI goes to the
> redistributor. Therefore, all we need from GIC is a method like
> inject_lpi(int lpi). Well, may be a couple more, for moving LPIs between
> collections. But this is not a problem and makes up a nice interface.
>  Even on the picture you mentioned ITS is a kind of separate thing. It can
> even be completely missing.
>
>  Well, my reasons end here. If you still disagree... Do what you want
> then, it will not be a problem to remove these unused stubs.
>  Peter, we are summoning you. :)
>
> Kind regards,
> Pavel Fedin
> Expert Engineer
> Samsung Electronics Research center Russia
>
>
>
Pavel Fedin Oct. 21, 2015, 2:41 p.m. UTC | #9
Hello!

> I just wanted to understand. I don't have any preferences.

 In other words, in short: spec says that ITS is optional, so we can implement it as a separate component, which gets attached to the GIC using some specified interface. It's not a problem to design such an interface. Actually, i believe real HW does the same thing.
 In my RFC i have implemented a part of this interface. My ITS class has gic-parent property, which is used to attach it to the GIC. KVM implementation fetches vGIC's fd from there, while software emulation can use it to call LPI methods on the GIC. The property is declared as implementation-specific only because it would have different object type, for additional fail-safety. Software-emulated ITS cannot be attached to KVM vGIC and vice versa, actually only because kernel guys don't want direct LPI injection.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
Peter Maydell Oct. 21, 2015, 2:46 p.m. UTC | #10
On 21 October 2015 at 15:41, Pavel Fedin <p.fedin@samsung.com> wrote:
>  Hello!
>
>> I just wanted to understand. I don't have any preferences.
>
>  In other words, in short: spec says that ITS is optional, so
> we can implement it as a separate component, which gets attached
> to the GIC using some specified interface. It's not a problem
> to design such an interface. Actually, i believe real HW does
> the same thing.

For hw it's a design choice: hardware can either have the ITS as
an extra component on the side that only talks to the
redistributors via (impdef) redistributor registers; or
it can be an integrated part of the GIC that's just directly
connected internally.

For QEMU we could in theory do either; I was leaning towards
direct connection just because on the KVM side the in-kernel
GIC isn't going to separate them out as two distinct things.
But even there we can as you say sensibly model the ITS
as its own QOM object with a fairly well-defined interface
to the rest of the GIC.

thanks
-- PMM
Pavel Fedin Oct. 21, 2015, 2:54 p.m. UTC | #11
Hello!

> For QEMU we could in theory do either; I was leaning towards
> direct connection just because on the KVM side the in-kernel
> GIC isn't going to separate them out as two distinct things.

 I'd say this is not entirely true. With KVM you still can have vGIC without vITS. Just don't set KVM_VGIC_V3_ADDR_TYPE_ITS and that's it. The only thing linked in is LPI support. With KVM you cannot have LPIs without vITS. Neither you can directly inject LPIs.
 So, in-kernel ITS is also optional.

Kind regards,
Pavel Fedin
Expert Engineer
Samsung Electronics Research center Russia
diff mbox

Patch

diff --git a/hw/intc/Makefile.objs b/hw/intc/Makefile.objs
index 5e56acc..0e6784f 100644
--- a/hw/intc/Makefile.objs
+++ b/hw/intc/Makefile.objs
@@ -17,6 +17,7 @@  common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_interrupts.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_cpu_interface.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_dist.o
 common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_redist.o
+common-obj-$(CONFIG_ARM_GIC) += arm_gicv3_spi_its.o
 common-obj-$(CONFIG_OPENPIC) += openpic.o
 
 obj-$(CONFIG_APIC) += apic.o apic_common.o
diff --git a/hw/intc/arm_gicv3_spi_its.c b/hw/intc/arm_gicv3_spi_its.c
new file mode 100644
index 0000000..cd2b56d
--- /dev/null
+++ b/hw/intc/arm_gicv3_spi_its.c
@@ -0,0 +1,359 @@ 
+#include "gicv3_internal.h"
+#include "qom/cpu.h"
+#include "arm_gicv3_spi_its.h"
+#include "arm_gicv3_interrupts.h"
+
+/* ITS routines are stubs for future development */
+static uint64_t gic_its_readb(void *opaque, hwaddr offset)
+{
+    return 0;
+}
+
+static uint64_t gic_its_readw(void *opaque, hwaddr offset)
+{
+    uint64_t val;
+    val = gic_its_readb(opaque, offset);
+    val |= gic_its_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint64_t gic_its_readl(void *opaque, hwaddr offset)
+{
+    uint64_t val;
+    val = gic_its_readw(opaque, offset);
+    val |= gic_its_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static uint64_t gic_its_readll(void *opaque, hwaddr offset)
+{
+    uint64_t val;
+    val = gic_its_readl(opaque, offset);
+    val |= gic_its_readl(opaque, offset + 4) << 32;
+    return val;
+}
+
+static void gic_its_writeb(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    GICv3State *s = (GICv3State *)opaque;
+    gicv3_update(s);
+    return;
+}
+
+static void gic_its_writew(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    gic_its_writeb(opaque, offset, value & 0xff);
+    gic_its_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void gic_its_writel(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    gic_its_writel(opaque, offset, value & 0xffff);
+    gic_its_writel(opaque, offset + 2, value >> 16);
+}
+
+static void gic_its_writell(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    gic_its_writell(opaque, offset, value & 0xffffffff);
+    gic_its_writell(opaque, offset + 4, value >> 32);
+}
+
+uint64_t gic_its_read(void *opaque, hwaddr addr, unsigned size)
+{
+    uint64_t data;
+    switch (size) {
+    case 1:
+        data = gic_its_readb(opaque, addr);
+        break;
+    case 2:
+        data = gic_its_readw(opaque, addr);
+        break;
+    case 4:
+        data = gic_its_readl(opaque, addr);
+        break;
+    case 8:
+        data = gic_its_readll(opaque, addr);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: size %u\n", __func__, size);
+        assert(0);
+        break;
+    }
+    DPRINTF("offset %p data %p\n", (void *) addr, (void *) data);
+    return data;
+}
+
+void gic_its_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
+{
+    DPRINTF("offset %p data %p\n", (void *) addr, (void *) data);
+    switch (size) {
+    case 1:
+        gic_its_writew(opaque, addr, data);
+        break;
+    case 2:
+        gic_its_writew(opaque, addr, data);
+        break;
+    case 4:
+        gic_its_writel(opaque, addr, data);
+        break;
+    case 8:
+        gic_its_writell(opaque, addr, data);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: size %u\n", __func__, size);
+        assert(0);
+        break;
+    }
+}
+
+/* SPI routines are stubs for future development */
+static uint64_t gic_spi_readb(void *opaque, hwaddr offset)
+{
+    return 0;
+}
+
+static uint64_t gic_spi_readw(void *opaque, hwaddr offset)
+{
+    uint64_t val;
+    val = gic_spi_readb(opaque, offset);
+    val |= gic_spi_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint64_t gic_spi_readl(void *opaque, hwaddr offset)
+{
+    uint64_t val;
+    val = gic_spi_readw(opaque, offset);
+    val |= gic_spi_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static uint64_t gic_spi_readll(void *opaque, hwaddr offset)
+{
+    uint64_t val;
+    val = gic_spi_readl(opaque, offset);
+    val |= gic_spi_readl(opaque, offset + 4) << 32;
+    return val;
+}
+
+static void gic_spi_writeb(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    GICv3State *s = (GICv3State *)opaque;
+    gicv3_update(s);
+    return;
+}
+
+static void gic_spi_writew(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    gic_spi_writeb(opaque, offset, value & 0xff);
+    gic_spi_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void gic_spi_writel(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    gic_spi_writew(opaque, offset, value & 0xffff);
+    gic_spi_writew(opaque, offset + 2, value >> 16);
+}
+
+static void gic_spi_writell(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    gic_spi_writel(opaque, offset, value & 0xffffffff);
+    gic_spi_writel(opaque, offset + 4, value >> 32);
+}
+
+uint64_t gic_spi_read(void *opaque, hwaddr addr, unsigned size)
+{
+    uint64_t data;
+    switch (size) {
+    case 1:
+        data = gic_spi_readb(opaque, addr);
+        break;
+    case 2:
+        data = gic_spi_readw(opaque, addr);
+        break;
+    case 4:
+        data = gic_spi_readl(opaque, addr);
+        break;
+    case 8:
+        data = gic_spi_readll(opaque, addr);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: size %u\n", __func__, size);
+        assert(0);
+        break;
+    }
+    DPRINTF("offset %p data %p\n", (void *) addr, (void *) data);
+    return data;
+}
+
+void gic_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
+{
+    DPRINTF("offset %p data %p\n", (void *) addr, (void *) data);
+    switch (size) {
+    case 1:
+        gic_spi_writeb(opaque, addr, data);
+        break;
+    case 2:
+        gic_spi_writew(opaque, addr, data);
+        break;
+    case 4:
+        gic_spi_writel(opaque, addr, data);
+        break;
+    case 8:
+        gic_spi_writell(opaque, addr, data);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: size %u\n", __func__, size);
+        assert(0);
+        break;
+    }
+}
+
+/* ITS control routines are stubs for future development */
+static uint64_t gic_its_cntrl_readb(void *opaque, hwaddr offset)
+{
+    GICv3State *s = (GICv3State *)opaque;
+    uint64_t res=0;
+
+    if (offset < 0x100) {
+          if (offset == 0)
+            return 0;
+          if (offset == 4)
+              return 0;
+          if (offset < 0x08)
+            return s->num_cpu;
+          if (offset >= 0x80) {
+            return 0;
+          }
+          goto bad_reg;
+      }
+    return res;
+bad_reg:
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "%s: Bad offset %x\n", __func__, (int)offset);
+    return 0;
+}
+
+static uint64_t gic_its_cntrl_readw(void *opaque, hwaddr offset)
+{
+    uint64_t val;
+    val = gic_its_cntrl_readb(opaque, offset);
+    val |= gic_its_cntrl_readb(opaque, offset + 1) << 8;
+    return val;
+}
+
+static uint64_t gic_its_cntrl_readl(void *opaque, hwaddr offset)
+{
+    uint64_t val;
+    val = gic_its_cntrl_readw(opaque, offset);
+    val |= gic_its_cntrl_readw(opaque, offset + 2) << 16;
+    return val;
+}
+
+static uint64_t gic_its_cntrl_readll(void *opaque, hwaddr offset)
+{
+    uint64_t val;
+    val = gic_its_cntrl_readl(opaque, offset);
+    val |= gic_its_cntrl_readl(opaque, offset + 4) << 32;
+    return val;
+}
+
+static void gic_its_cntrl_writeb(void *opaque, hwaddr offset,
+                                 uint64_t value)
+{
+    GICv3State *s = (GICv3State *)opaque;
+    if (offset < 0x100) {
+        if (offset < 0x08)
+            s->num_cpu = value;
+        else
+            goto bad_reg;
+    }
+    gicv3_update(s);
+    return;
+bad_reg:
+    qemu_log_mask(LOG_GUEST_ERROR,
+                  "%s: Bad offset %x\n", __func__, (int)offset);
+}
+
+static void gic_its_cntrl_writew(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    gic_its_cntrl_writeb(opaque, offset, value & 0xff);
+    gic_its_cntrl_writeb(opaque, offset + 1, value >> 8);
+}
+
+static void gic_its_cntrl_writel(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    gic_its_cntrl_writew(opaque, offset, value & 0xffff);
+    gic_its_cntrl_writew(opaque, offset + 2, value >> 16);
+}
+
+static void gic_its_cntrl_writell(void *opaque, hwaddr offset,
+                            uint64_t value)
+{
+    gic_its_cntrl_writel(opaque, offset, value & 0xffffffff);
+    gic_its_cntrl_writel(opaque, offset + 4, value >> 32);
+}
+
+uint64_t gic_its_cntrl_read(void *opaque, hwaddr addr, unsigned size)
+{
+    uint64_t data;
+    switch (size) {
+    case 1:
+        data = gic_its_cntrl_readb(opaque, addr);
+        break;
+    case 2:
+        data = gic_its_cntrl_readw(opaque, addr);
+        break;
+    case 4:
+        data = gic_its_cntrl_readl(opaque, addr);
+        break;
+    case 8:
+        data = gic_its_cntrl_readll(opaque, addr);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: size %u\n", __func__, size);
+        assert(0);
+        break;
+    }
+    DPRINTF("offset %p data %p\n", (void *) addr, (void *) data);
+    return data;
+}
+
+void gic_its_cntrl_write(void *opaque, hwaddr addr, uint64_t data, unsigned size)
+{
+    DPRINTF("offset %p data %p\n", (void *) addr, (void *) data);
+    switch (size) {
+    case 1:
+        gic_its_cntrl_writeb(opaque, addr, data);
+        break;
+    case 2:
+        gic_its_cntrl_writew(opaque, addr, data);
+        break;
+    case 4:
+        gic_its_cntrl_writel(opaque, addr, data);
+        break;
+    case 8:
+        gic_its_cntrl_writell(opaque, addr, data);
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+                      "%s: size %u\n", __func__, size);
+        assert(0);
+        break;
+    }
+}
diff --git a/hw/intc/arm_gicv3_spi_its.h b/hw/intc/arm_gicv3_spi_its.h
new file mode 100644
index 0000000..18e7c4b
--- /dev/null
+++ b/hw/intc/arm_gicv3_spi_its.h
@@ -0,0 +1,11 @@ 
+#ifndef QEMU_ARM_GICV3_SPI_ITS_H
+#define QEMU_ARM_GICV3_SPI_ITS_H
+
+uint64_t gic_its_read(void *opaque, hwaddr addr, unsigned size);
+void gic_its_write(void *opaque, hwaddr addr, uint64_t data, unsigned size);
+uint64_t gic_spi_read(void *opaque, hwaddr addr, unsigned size);
+void gic_spi_write(void *opaque, hwaddr addr, uint64_t data, unsigned size);
+uint64_t gic_its_cntrl_read(void *opaque, hwaddr addr, unsigned size);
+void gic_its_cntrl_write(void *opaque, hwaddr addr, uint64_t data, unsigned size);
+
+#endif /* !QEMU_ARM_GIC_SPI_ITS_H */