Patchwork [19/26] Add PAPR H_VIO_SIGNAL hypercall and infrastructure for VIO interrupts

login
register
mail settings
Submitter David Gibson
Date March 16, 2011, 4:56 a.m.
Message ID <1300251423-6715-20-git-send-email-david@gibson.dropbear.id.au>
Download mbox | patch
Permalink /patch/87159/
State New
Headers show

Comments

David Gibson - March 16, 2011, 4:56 a.m.
This patch adds infrastructure to support interrupts from PAPR virtual IO
devices.  This includes correctly advertising those interrupts in the
device tree, and implementing the H_VIO_SIGNAL hypercall, used to
enable and disable individual device interrupts.

Signed-off-by: David Gibson <dwg@au1.ibm.com>
---
 hw/spapr.c     |    2 +-
 hw/spapr_vio.c |   34 ++++++++++++++++++++++++++++++++++
 hw/spapr_vio.h |    6 ++++++
 3 files changed, 41 insertions(+), 1 deletions(-)
Alexander Graf - March 16, 2011, 3:49 p.m.
On 03/16/2011 05:56 AM, David Gibson wrote:
> This patch adds infrastructure to support interrupts from PAPR virtual IO
> devices.  This includes correctly advertising those interrupts in the
> device tree, and implementing the H_VIO_SIGNAL hypercall, used to
> enable and disable individual device interrupts.
>
> Signed-off-by: David Gibson<dwg@au1.ibm.com>
> ---
>   hw/spapr.c     |    2 +-
>   hw/spapr_vio.c |   34 ++++++++++++++++++++++++++++++++++
>   hw/spapr_vio.h |    6 ++++++
>   3 files changed, 41 insertions(+), 1 deletions(-)
>
> diff --git a/hw/spapr.c b/hw/spapr.c
> index be30def..5b19963 100644
> --- a/hw/spapr.c
> +++ b/hw/spapr.c
> @@ -62,7 +62,7 @@ static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
>       uint32_t start_prop = cpu_to_be32(initrd_base);
>       uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
>       uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
> -    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr";
> +    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt";
>       uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
>       int i;
>       char *modelname;
> diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
> index 0ed63f4..45edd94 100644
> --- a/hw/spapr_vio.c
> +++ b/hw/spapr_vio.c
> @@ -105,6 +105,15 @@ static int vio_make_devnode(VIOsPAPRDevice *dev,
>           }
>       }
>
> +    if (dev->qirq) {
> +        uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
> +
> +        ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
> +                          sizeof(ints_prop));
> +        if (ret<  0)

Braces

> +            return ret;
> +    }
> +
>       if (info->devnode) {
>           ret = (info->devnode)(dev, fdt, node_off);
>           if (ret<  0) {
> @@ -140,6 +149,28 @@ void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
>       qdev_register(&info->qdev);
>   }
>
> +static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
> +                                 target_ulong opcode,
> +                                 target_ulong *args)
> +{
> +    target_ulong reg = args[0];
> +    target_ulong mode = args[1];
> +    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
> +    VIOsPAPRDeviceInfo *info;
> +
> +    if (!dev)

Braces

> +        return H_PARAMETER;
> +
> +    info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
> +
> +    if (mode&  ~info->signal_mask)

Braces

> +        return H_PARAMETER;;
> +
> +    dev->signal_state = mode;

No need to notify the device?


Alex
David Gibson - March 17, 2011, 1:38 a.m.
On Wed, Mar 16, 2011 at 04:49:07PM +0100, Alexander Graf wrote:
> On 03/16/2011 05:56 AM, David Gibson wrote:
[snip]
> >+        return H_PARAMETER;;
> >+
> >+    dev->signal_state = mode;
> 
> No need to notify the device?

No, at the point it would send an interrupt the device checks
signal_state.

That said, I was considering another cleanup to the signal code to
have the devices use a helper function checking signal_state, and also
allowing multiple interrupts for a VIO device.  Not sure if it's worth
folding that into this series or doing it as a later extension.
Alexander Graf - March 17, 2011, 7:38 a.m.
On 17.03.2011, at 02:38, David Gibson <david@gibson.dropbear.id.au> wrote:

> On Wed, Mar 16, 2011 at 04:49:07PM +0100, Alexander Graf wrote:
>> On 03/16/2011 05:56 AM, David Gibson wrote:
> [snip]
>>> +        return H_PARAMETER;;
>>> +
>>> +    dev->signal_state = mode;
>> 
>> No need to notify the device?
> 
> No, at the point it would send an interrupt the device checks
> signal_state.
> 
> That said, I was considering another cleanup to the signal code to
> have the devices use a helper function checking signal_state, and also
> allowing multiple interrupts for a VIO device.  Not sure if it's worth
> folding that into this series or doing it as a later extension.

It's fine to leave it as is for now.

>

Patch

diff --git a/hw/spapr.c b/hw/spapr.c
index be30def..5b19963 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -62,7 +62,7 @@  static void *spapr_create_fdt(int *fdt_size, ram_addr_t ramsize,
     uint32_t start_prop = cpu_to_be32(initrd_base);
     uint32_t end_prop = cpu_to_be32(initrd_base + initrd_size);
     uint32_t pft_size_prop[] = {0, cpu_to_be32(hash_shift)};
-    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr";
+    char hypertas_prop[] = "hcall-pft\0hcall-term\0hcall-dabr\0hcall-interrupt";
     uint32_t interrupt_server_ranges_prop[] = {0, cpu_to_be32(smp_cpus)};
     int i;
     char *modelname;
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 0ed63f4..45edd94 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -105,6 +105,15 @@  static int vio_make_devnode(VIOsPAPRDevice *dev,
         }
     }
 
+    if (dev->qirq) {
+        uint32_t ints_prop[] = {cpu_to_be32(dev->vio_irq_num), 0};
+
+        ret = fdt_setprop(fdt, node_off, "interrupts", ints_prop,
+                          sizeof(ints_prop));
+        if (ret < 0)
+            return ret;
+    }
+
     if (info->devnode) {
         ret = (info->devnode)(dev, fdt, node_off);
         if (ret < 0) {
@@ -140,6 +149,28 @@  void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info)
     qdev_register(&info->qdev);
 }
 
+static target_ulong h_vio_signal(CPUState *env, sPAPREnvironment *spapr,
+                                 target_ulong opcode,
+                                 target_ulong *args)
+{
+    target_ulong reg = args[0];
+    target_ulong mode = args[1];
+    VIOsPAPRDevice *dev = spapr_vio_find_by_reg(spapr->vio_bus, reg);
+    VIOsPAPRDeviceInfo *info;
+
+    if (!dev)
+        return H_PARAMETER;
+
+    info = (VIOsPAPRDeviceInfo *)dev->qdev.info;
+
+    if (mode & ~info->signal_mask)
+        return H_PARAMETER;;
+
+    dev->signal_state = mode;
+
+    return H_SUCCESS;
+}
+
 VIOsPAPRBus *spapr_vio_bus_init(void)
 {
     VIOsPAPRBus *bus;
@@ -156,6 +187,9 @@  VIOsPAPRBus *spapr_vio_bus_init(void)
     _bus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
     bus = DO_UPCAST(VIOsPAPRBus, bus, _bus);
 
+    /* hcall-vio */
+    spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
+
     for (_info = device_info_list; _info; _info = _info->next) {
         VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)_info;
 
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index b164ad3..8a000c6 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -24,6 +24,9 @@ 
 typedef struct VIOsPAPRDevice {
     DeviceState qdev;
     uint32_t reg;
+    qemu_irq qirq;
+    uint32_t vio_irq_num;
+    target_ulong signal_state;
 } VIOsPAPRDevice;
 
 typedef struct VIOsPAPRBus {
@@ -33,6 +36,7 @@  typedef struct VIOsPAPRBus {
 typedef struct {
     DeviceInfo qdev;
     const char *dt_name, *dt_type, *dt_compatible;
+    target_ulong signal_mask;
     int (*init)(VIOsPAPRDevice *dev);
     void (*hcalls)(VIOsPAPRBus *bus);
     int (*devnode)(VIOsPAPRDevice *dev, void *fdt, int node_off);
@@ -43,6 +47,8 @@  extern VIOsPAPRDevice *spapr_vio_find_by_reg(VIOsPAPRBus *bus, uint32_t reg);
 extern void spapr_vio_bus_register_withprop(VIOsPAPRDeviceInfo *info);
 extern int spapr_populate_vdevice(VIOsPAPRBus *bus, void *fdt);
 
+extern int spapr_vio_signal(VIOsPAPRDevice *dev, target_ulong mode);
+
 void vty_putchars(VIOsPAPRDevice *sdev, uint8_t *buf, int len);
 void spapr_vty_create(VIOsPAPRBus *bus,
                       uint32_t reg, CharDriverState *chardev);