diff --git a/hw/spapr.c b/hw/spapr.c
index deb4ae5417..b1189755d3 100644
--- a/hw/spapr.c
+++ b/hw/spapr.c
@@ -61,6 +61,30 @@
 
 sPAPREnvironment *spapr;
 
+qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num)
+{
+    uint32_t irq;
+    qemu_irq qirq;
+
+    if (hint) {
+        irq = hint;
+        /* FIXME: we should probably check for collisions somehow */
+    } else {
+        irq = spapr->next_irq++;
+    }
+
+    qirq = xics_find_qirq(spapr->icp, irq);
+    if (!qirq) {
+        return NULL;
+    }
+
+    if (irq_num) {
+        *irq_num = irq;
+    }
+
+    return qirq;
+}
+
 static void *spapr_create_fdt_skel(const char *cpu_model,
                                    target_phys_addr_t initrd_base,
                                    target_phys_addr_t initrd_size,
@@ -372,6 +396,7 @@ static void ppc_spapr_init(ram_addr_t ram_size,
 
     /* Set up Interrupt Controller */
     spapr->icp = xics_system_init(XICS_IRQS);
+    spapr->next_irq = 16;
 
     /* Set up VIO bus */
     spapr->vio_bus = spapr_vio_bus_init();
diff --git a/hw/spapr.h b/hw/spapr.h
index 3d21b7a1cc..ec910de5b0 100644
--- a/hw/spapr.h
+++ b/hw/spapr.h
@@ -17,6 +17,7 @@ typedef struct sPAPREnvironment {
     long rtas_size;
     void *fdt_skel;
     target_ulong entry_point;
+    int next_irq;
 } sPAPREnvironment;
 
 #define H_SUCCESS         0
@@ -281,11 +282,7 @@ void spapr_register_hypercall(target_ulong opcode, spapr_hcall_fn fn);
 target_ulong spapr_hypercall(CPUState *env, target_ulong opcode,
                              target_ulong *args);
 
-static inline qemu_irq spapr_find_qirq(sPAPREnvironment *spapr,
-                                        int irq_num)
-{
-    return xics_find_qirq(spapr->icp, irq_num);
-}
+qemu_irq spapr_allocate_irq(uint32_t hint, uint32_t *irq_num);
 
 static inline uint32_t rtas_ld(target_ulong phys, int n)
 {
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 0546ccb043..35818e18f1 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -600,7 +600,6 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
 {
     VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
     VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
-    VIOsPAPRBus *bus = DO_UPCAST(VIOsPAPRBus, bus, dev->qdev.parent_bus);
     char *id;
 
     if (asprintf(&id, "%s@%x", info->dt_name, dev->reg) < 0) {
@@ -608,10 +607,11 @@ static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
     }
 
     dev->qdev.id = id;
-    if (!dev->vio_irq_num) {
-        dev->vio_irq_num = bus->irq++;
+
+    dev->qirq = spapr_allocate_irq(dev->vio_irq_num, &dev->vio_irq_num);
+    if (!dev->qirq) {
+        return -1;
     }
-    dev->qirq = spapr_find_qirq(spapr, dev->vio_irq_num);
 
     rtce_init(dev);
 
@@ -666,7 +666,6 @@ VIOsPAPRBus *spapr_vio_bus_init(void)
 
     qbus = qbus_create(&spapr_vio_bus_info, dev, "spapr-vio");
     bus = DO_UPCAST(VIOsPAPRBus, bus, qbus);
-    bus->irq = 16;
 
     /* hcall-vio */
     spapr_register_hypercall(H_VIO_SIGNAL, h_vio_signal);
diff --git a/hw/spapr_vio.h b/hw/spapr_vio.h
index 7eb5367653..4fe5f742c2 100644
--- a/hw/spapr_vio.h
+++ b/hw/spapr_vio.h
@@ -67,7 +67,6 @@ typedef struct VIOsPAPRDevice {
 
 typedef struct VIOsPAPRBus {
     BusState bus;
-    int irq;
 } VIOsPAPRBus;
 
 typedef struct {