summary refs log tree commit diff stats
path: root/hw/spapr_vio.c
diff options
context:
space:
mode:
Diffstat (limited to 'hw/spapr_vio.c')
-rw-r--r--hw/spapr_vio.c32
1 files changed, 32 insertions, 0 deletions
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index cd03416958..7a86dc8d2c 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -621,11 +621,43 @@ static void rtas_quiesce(sPAPREnvironment *spapr, uint32_t token,
     rtas_st(rets, 0, 0);
 }
 
+static int spapr_vio_check_reg(VIOsPAPRDevice *sdev, VIOsPAPRDeviceInfo *info)
+{
+    VIOsPAPRDevice *other_sdev;
+    DeviceState *qdev;
+    VIOsPAPRBus *sbus;
+
+    sbus = DO_UPCAST(VIOsPAPRBus, bus, sdev->qdev.parent_bus);
+
+    /*
+     * Check two device aren't given clashing addresses by the user (or some
+     * other mechanism). We have to open code this because we have to check
+     * for matches with devices other than us.
+     */
+    QTAILQ_FOREACH(qdev, &sbus->bus.children, sibling) {
+        other_sdev = DO_UPCAST(VIOsPAPRDevice, qdev, qdev);
+
+        if (other_sdev != sdev && other_sdev->reg == sdev->reg) {
+            fprintf(stderr, "vio: %s and %s devices conflict at address %#x\n",
+                    info->qdev.name, other_sdev->qdev.info->name, sdev->reg);
+            return -EEXIST;
+        }
+    }
+
+    return 0;
+}
+
 static int spapr_vio_busdev_init(DeviceState *qdev, DeviceInfo *qinfo)
 {
     VIOsPAPRDeviceInfo *info = (VIOsPAPRDeviceInfo *)qinfo;
     VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
     char *id;
+    int ret;
+
+    ret = spapr_vio_check_reg(dev, info);
+    if (ret) {
+        return ret;
+    }
 
     /* Don't overwrite ids assigned on the command line */
     if (!dev->qdev.id) {