aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Gibson <david@gibson.dropbear.id.au>2012-03-29 08:39:46 +1100
committerAndreas Färber <afaerber@suse.de>2012-04-15 17:07:19 +0200
commit8e01f355db4c7e54b0877a6d9508e83d0afbc4b6 (patch)
tree575b675caf78fcc6f2f223d065f8b8ef9524e6a4
parentd9599c9205089805cd6ef55985beeb06aef0c819 (diff)
pseries: Fix bug with reset of VIO CRQs
PAPR specifies a Command Response Queue (CRQ) mechanism used for virtual IO, which we implement. However, we don't correctly clean up registered CRQs when we reset the system. This patch adds a reset handler to fix this bug. While we're at it, add in some of the extra debug messages that were used to track the problem down. Signed-off-by: David Gibson <david@gibson.dropbear.id.au> [AF: Updated hcall_dprintf()s to not duplicate the function name] Signed-off-by: Andreas Färber <afaerber@suse.de>
-rw-r--r--hw/spapr_vio.c33
1 files changed, 25 insertions, 8 deletions
diff --git a/hw/spapr_vio.c b/hw/spapr_vio.c
index 1f67e64eb6..0bf2c3179c 100644
--- a/hw/spapr_vio.c
+++ b/hw/spapr_vio.c
@@ -431,12 +431,13 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
/* Check if device supports CRQs */
if (!dev->crq.SendFunc) {
+ hcall_dprintf("Device does not support CRQ\n");
return H_NOT_FOUND;
}
-
/* Already a queue ? */
if (dev->crq.qsize) {
+ hcall_dprintf("CRQ already registered\n");
return H_RESOURCE;
}
dev->crq.qladdr = queue_addr;
@@ -449,6 +450,17 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
return H_SUCCESS;
}
+static target_ulong free_crq(VIOsPAPRDevice *dev)
+{
+ dev->crq.qladdr = 0;
+ dev->crq.qsize = 0;
+ dev->crq.qnext = 0;
+
+ dprintf("CRQ for dev 0x%" PRIx32 " freed\n", dev->reg);
+
+ return H_SUCCESS;
+}
+
static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args)
{
@@ -460,13 +472,7 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
return H_PARAMETER;
}
- dev->crq.qladdr = 0;
- dev->crq.qsize = 0;
- dev->crq.qnext = 0;
-
- dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg);
-
- return H_SUCCESS;
+ return free_crq(dev);
}
static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
@@ -642,6 +648,15 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
return 0;
}
+static void spapr_vio_busdev_reset(void *opaque)
+{
+ VIOsPAPRDevice *dev = (VIOsPAPRDevice *)opaque;
+
+ if (dev->crq.qsize) {
+ free_crq(dev);
+ }
+}
+
static int spapr_vio_busdev_init(DeviceState *qdev)
{
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
@@ -670,6 +685,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
rtce_init(dev);
+ qemu_register_reset(spapr_vio_busdev_reset, dev);
+
return pc->init(dev);
}