diff mbox series

[09/25] spapr: introduce handlers for XIVE interrupt sources

Message ID 20171123132955.1261-10-clg@kaod.org
State New
Headers show
Series spapr: Guest exploitation of the XIVE interrupt controller (POWER9) | expand

Commit Message

Cédric Le Goater Nov. 23, 2017, 1:29 p.m. UTC
These are very similar to the XICS handlers in a simpler form. They make
use of a status array for the LSI interrupts. The spapr_xive_irq() routine
in charge of triggering the CPU interrupt line will be filled later on.

Signed-off-by: Cédric Le Goater <clg@kaod.org>
---
 hw/intc/spapr_xive.c        | 55 +++++++++++++++++++++++++++++++++++++++++++--
 include/hw/ppc/spapr_xive.h | 14 +++++++++++-
 2 files changed, 66 insertions(+), 3 deletions(-)

Comments

David Gibson Nov. 28, 2017, 5:45 a.m. UTC | #1
On Thu, Nov 23, 2017 at 02:29:39PM +0100, Cédric Le Goater wrote:
> These are very similar to the XICS handlers in a simpler form. They make
> use of a status array for the LSI interrupts. The spapr_xive_irq() routine
> in charge of triggering the CPU interrupt line will be filled later on.
> 
> Signed-off-by: Cédric Le Goater <clg@kaod.org>

Is the status word you add here architected as part of the XIVE spec,
or purely internal / implementation specific?

> ---
>  hw/intc/spapr_xive.c        | 55 +++++++++++++++++++++++++++++++++++++++++++--
>  include/hw/ppc/spapr_xive.h | 14 +++++++++++-
>  2 files changed, 66 insertions(+), 3 deletions(-)
> 
> 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;

How does a hardware XIVE know which irqs are LSI and which are MSI?

>      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);
>
Cédric Le Goater Nov. 28, 2017, 6:18 p.m. UTC | #2
On 11/28/2017 05:45 AM, David Gibson wrote:
> On Thu, Nov 23, 2017 at 02:29:39PM +0100, Cédric Le Goater wrote:
>> These are very similar to the XICS handlers in a simpler form. They make
>> use of a status array for the LSI interrupts. The spapr_xive_irq() routine
>> in charge of triggering the CPU interrupt line will be filled later on.
>>
>> Signed-off-by: Cédric Le Goater <clg@kaod.org>
> 
> Is the status word you add here architected as part of the XIVE spec,
> or purely internal / implementation specific?

this is the model.

> 
>> ---
>>  hw/intc/spapr_xive.c        | 55 +++++++++++++++++++++++++++++++++++++++++++--
>>  include/hw/ppc/spapr_xive.h | 14 +++++++++++-
>>  2 files changed, 66 insertions(+), 3 deletions(-)
>>
>> 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;
> 
> How does a hardware XIVE know which irqs are LSI and which are MSI?

AFAICT, it doesn't. LSI events are configured as the other XIVE interrupts. 
The level is converted in the P bit and the Q bit should always be zero.
So I should be able to simplify the proposed model which still is mimicking 
XICS  ... I will take a look at it. 

There are a sort of special degenerated LSIs but these are for bringup.

Thanks,

C. 

>>      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);
>>  
>
Benjamin Herrenschmidt Dec. 2, 2017, 2:26 p.m. UTC | #3
On Tue, 2017-11-28 at 18:18 +0000, Cédric Le Goater wrote:
> AFAICT, it doesn't. LSI events are configured as the other XIVE interrupts. 
> The level is converted in the P bit and the Q bit should always be zero.
> So I should be able to simplify the proposed model which still is mimicking 
> XICS  ... I will take a look at it. 
> 
> There are a sort of special degenerated LSIs but these are for bringup.

Not really. So for MSIs you don't need your state flags.

For LSIs, you do need the "asserted" one that keeps track of the LSI
input state. See my other note with the actual states.

Cheers,
Ben.
diff mbox series

Patch

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);