aboutsummaryrefslogtreecommitdiff
path: root/hw/ppc/spapr_vio.c
diff options
context:
space:
mode:
authorCédric Le Goater <clg@kaod.org>2018-07-30 16:11:32 +0200
committerDavid Gibson <david@gibson.dropbear.id.au>2018-08-21 14:28:45 +1000
commit82cffa2eb255731b8402e206d0434cc884d99e54 (patch)
tree763ef42808493580b1716ad8968162d43c6b743a /hw/ppc/spapr_vio.c
parentd45360d93d71578919ae8065a142beb941a900fd (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.c66
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);