diff --git a/hw/intc/spapr_xive.c b/hw/intc/spapr_xive.c
index b2fc3007c85f..66c533fb1d78 100644
--- a/hw/intc/spapr_xive.c
+++ b/hw/intc/spapr_xive.c
@@ -26,6 +26,47 @@
 
 #include "xive-internal.h"
 
+static void spapr_xive_irq(sPAPRXive *xive, int lisn)
+{
+
+}
+
+/*
+ * XIVE Interrupt Source
+ */
+static void spapr_xive_source_set_irq_msi(sPAPRXive *xive, int lisn, int val)
+{
+    if (val) {
+        spapr_xive_irq(xive, lisn);
+    }
+}
+
+static void spapr_xive_source_set_irq_lsi(sPAPRXive *xive, int lisn, int val)
+{
+    if (val) {
+        xive->status[lisn] |= XIVE_STATUS_ASSERTED;
+    } else {
+        xive->status[lisn] &= ~XIVE_STATUS_ASSERTED;
+    }
+
+    if (xive->status[lisn] & XIVE_STATUS_ASSERTED &&
+        !(xive->status[lisn] & XIVE_STATUS_SENT)) {
+        xive->status[lisn] |= XIVE_STATUS_SENT;
+        spapr_xive_irq(xive, lisn);
+    }
+}
+
+static void spapr_xive_source_set_irq(void *opaque, int lisn, int val)
+{
+    sPAPRXive *xive = SPAPR_XIVE(opaque);
+
+    if (spapr_xive_irq_is_lsi(xive, lisn)) {
+        spapr_xive_source_set_irq_lsi(xive, lisn, val);
+    } else {
+        spapr_xive_source_set_irq_msi(xive, lisn, val);
+    }
+}
+
 /*
  * Main XIVE object
  */
@@ -41,7 +82,8 @@ void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon)
             continue;
         }
 
-        monitor_printf(mon, "  %4x %s %08x %08x\n", i,
+        monitor_printf(mon, "  %4x %s %s %08x %08x\n", i,
+                       spapr_xive_irq_is_lsi(xive, i) ? "LSI" : "MSI",
                        ive->w & IVE_MASKED ? "M" : " ",
                        (int) GETFIELD(IVE_EQ_INDEX, ive->w),
                        (int) GETFIELD(IVE_EQ_DATA, ive->w));
@@ -53,6 +95,8 @@ void spapr_xive_reset(void *dev)
     sPAPRXive *xive = SPAPR_XIVE(dev);
     int i;
 
+    /* Do not clear IRQs status */
+
     /* Mask all valid IVEs in the IRQ number space. */
     for (i = 0; i < xive->nr_irqs; i++) {
         XiveIVE *ive = &xive->ivt[i];
@@ -71,6 +115,11 @@ static void spapr_xive_realize(DeviceState *dev, Error **errp)
         return;
     }
 
+    /* QEMU IRQs */
+    xive->qirqs = qemu_allocate_irqs(spapr_xive_source_set_irq, xive,
+                                     xive->nr_irqs);
+    xive->status = g_malloc0(xive->nr_irqs);
+
     /* Allocate the IVT (Interrupt Virtualization Table) */
     xive->ivt = g_malloc0(xive->nr_irqs * sizeof(XiveIVE));
 
@@ -102,6 +151,7 @@ static const VMStateDescription vmstate_spapr_xive = {
         VMSTATE_UINT32_EQUAL(nr_irqs, sPAPRXive, NULL),
         VMSTATE_STRUCT_VARRAY_UINT32_ALLOC(ivt, sPAPRXive, nr_irqs, 1,
                                            vmstate_spapr_xive_ive, XiveIVE),
+        VMSTATE_VBUFFER_UINT32(status, sPAPRXive, 1, NULL, nr_irqs),
         VMSTATE_END_OF_LIST()
     },
 };
@@ -140,7 +190,7 @@ XiveIVE *spapr_xive_get_ive(sPAPRXive *xive, uint32_t lisn)
     return lisn < xive->nr_irqs ? &xive->ivt[lisn] : NULL;
 }
 
-bool spapr_xive_irq_set(sPAPRXive *xive, uint32_t lisn)
+bool spapr_xive_irq_set(sPAPRXive *xive, uint32_t lisn, bool lsi)
 {
     XiveIVE *ive = spapr_xive_get_ive(xive, lisn);
 
@@ -149,6 +199,7 @@ bool spapr_xive_irq_set(sPAPRXive *xive, uint32_t lisn)
     }
 
     ive->w |= IVE_VALID;
+    xive->status[lisn] |= lsi ? XIVE_STATUS_LSI : 0;
     return true;
 }
 
diff --git a/include/hw/ppc/spapr_xive.h b/include/hw/ppc/spapr_xive.h
index 795b3f4ded7c..6a799cdaba66 100644
--- a/include/hw/ppc/spapr_xive.h
+++ b/include/hw/ppc/spapr_xive.h
@@ -33,11 +33,23 @@ struct sPAPRXive {
     /* Properties */
     uint32_t     nr_irqs;
 
+     /* IRQ */
+    qemu_irq     *qirqs;
+#define XIVE_STATUS_LSI                0x1
+#define XIVE_STATUS_ASSERTED           0x2
+#define XIVE_STATUS_SENT               0x4
+    uint8_t      *status;
+
     /* XIVE internal tables */
     XiveIVE      *ivt;
 };
 
-bool spapr_xive_irq_set(sPAPRXive *xive, uint32_t lisn);
+static inline bool spapr_xive_irq_is_lsi(sPAPRXive *xive, int lisn)
+{
+    return xive->status[lisn] & XIVE_STATUS_LSI;
+}
+
+bool spapr_xive_irq_set(sPAPRXive *xive, uint32_t lisn, bool lsi);
 bool spapr_xive_irq_unset(sPAPRXive *xive, uint32_t lisn);
 void spapr_xive_pic_print_info(sPAPRXive *xive, Monitor *mon);
 
