diff options
author | Cédric Le Goater <clg@kaod.org> | 2018-07-30 16:11:32 +0200 |
---|---|---|
committer | David Gibson <david@gibson.dropbear.id.au> | 2018-08-21 14:28:45 +1000 |
commit | 82cffa2eb255731b8402e206d0434cc884d99e54 (patch) | |
tree | 763ef42808493580b1716ad8968162d43c6b743a /hw/ppc/spapr_vio.c | |
parent | d45360d93d71578919ae8065a142beb941a900fd (diff) |
spapr: introduce a fixed IRQ number space
This proposal introduces a new IRQ number space layout using static
numbers for all devices, depending on a device index, and a bitmap
allocator for the MSI IRQ numbers which are negotiated by the guest at
runtime.
As the VIO device model does not have a device index but a "reg"
property, we introduce a formula to compute an IRQ number from a "reg"
value. It should minimize most of the collisions.
The previous layout is kept in pre-3.1 machines raising the
'legacy_irq_allocation' machine class flag.
Signed-off-by: Cédric Le Goater <clg@kaod.org>
Reviewed-by: Greg Kurz <groug@kaod.org>
Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
Diffstat (limited to 'hw/ppc/spapr_vio.c')
-rw-r--r-- | hw/ppc/spapr_vio.c | 66 |
1 files changed, 60 insertions, 6 deletions
diff --git a/hw/ppc/spapr_vio.c b/hw/ppc/spapr_vio.c index be9af71437..840d4a3c45 100644 --- a/hw/ppc/spapr_vio.c +++ b/hw/ppc/spapr_vio.c @@ -37,12 +37,13 @@ #include "hw/ppc/spapr.h" #include "hw/ppc/spapr_vio.h" -#include "hw/ppc/xics.h" #include "hw/ppc/fdt.h" #include "trace.h" #include <libfdt.h> +#define SPAPR_VIO_REG_BASE 0x71000000 + static void spapr_vio_get_irq(Object *obj, Visitor *v, const char *name, void *opaque, Error **errp) { @@ -445,6 +446,55 @@ static void spapr_vio_busdev_reset(DeviceState *qdev) } } +/* + * The register property of a VIO device is defined in livirt using + * 0x1000 as a base register number plus a 0x1000 increment. For the + * VIO tty device, the base number is changed to 0x30000000. QEMU uses + * a base register number of 0x71000000 and then a simple increment. + * + * The formula below tries to compute a unique index number from the + * register value that will be used to define the IRQ number of the + * VIO device. + * + * A maximum of 256 VIO devices is covered. Collisions are possible + * but they will be detected when the IRQ is claimed. + */ +static inline uint32_t spapr_vio_reg_to_irq(uint32_t reg) +{ + uint32_t irq; + + if (reg >= SPAPR_VIO_REG_BASE) { + /* + * VIO device register values when allocated by QEMU. For + * these, we simply mask the high bits to fit the overall + * range: [0x00 - 0xff]. + * + * The nvram VIO device (reg=0x71000000) is a static device of + * the pseries machine and so is always allocated by QEMU. Its + * IRQ number is 0x0. + */ + irq = reg & 0xff; + + } else if (reg >= 0x30000000) { + /* + * VIO tty devices register values, when allocated by livirt, + * are mapped in range [0xf0 - 0xff], gives us a maximum of 16 + * vtys. + */ + irq = 0xf0 | ((reg >> 12) & 0xf); + + } else { + /* + * Other VIO devices register values, when allocated by + * livirt, should be mapped in range [0x00 - 0xef]. Conflicts + * will be detected when IRQ is claimed. + */ + irq = (reg >> 12) & 0xff; + } + + return SPAPR_IRQ_VIO | irq; +} + static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) { sPAPRMachineState *spapr = SPAPR_MACHINE(qdev_get_machine()); @@ -485,10 +535,14 @@ static void spapr_vio_busdev_realize(DeviceState *qdev, Error **errp) } if (!dev->irq) { - dev->irq = spapr_irq_findone(spapr, &local_err); - if (local_err) { - error_propagate(errp, local_err); - return; + dev->irq = spapr_vio_reg_to_irq(dev->reg); + + if (SPAPR_MACHINE_GET_CLASS(spapr)->legacy_irq_allocation) { + dev->irq = spapr_irq_findone(spapr, &local_err); + if (local_err) { + error_propagate(errp, local_err); + return; + } } } @@ -557,7 +611,7 @@ VIOsPAPRBus *spapr_vio_bus_init(void) /* Create bus on bridge device */ qbus = qbus_create(TYPE_SPAPR_VIO_BUS, dev, "spapr-vio"); bus = SPAPR_VIO_BUS(qbus); - bus->next_reg = 0x71000000; + bus->next_reg = SPAPR_VIO_REG_BASE; /* hcall-vio */ spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal); |