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>
This commit is contained in:
David Gibson 2012-03-29 08:39:46 +11:00 committed by Andreas Färber
parent d9599c9205
commit 8e01f355db

View File

@ -431,12 +431,13 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
/* Check if device supports CRQs */ /* Check if device supports CRQs */
if (!dev->crq.SendFunc) { if (!dev->crq.SendFunc) {
hcall_dprintf("Device does not support CRQ\n");
return H_NOT_FOUND; return H_NOT_FOUND;
} }
/* Already a queue ? */ /* Already a queue ? */
if (dev->crq.qsize) { if (dev->crq.qsize) {
hcall_dprintf("CRQ already registered\n");
return H_RESOURCE; return H_RESOURCE;
} }
dev->crq.qladdr = queue_addr; dev->crq.qladdr = queue_addr;
@ -449,6 +450,17 @@ static target_ulong h_reg_crq(CPUPPCState *env, sPAPREnvironment *spapr,
return H_SUCCESS; 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, static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
target_ulong opcode, target_ulong *args) target_ulong opcode, target_ulong *args)
{ {
@ -460,13 +472,7 @@ static target_ulong h_free_crq(CPUPPCState *env, sPAPREnvironment *spapr,
return H_PARAMETER; return H_PARAMETER;
} }
dev->crq.qladdr = 0; return free_crq(dev);
dev->crq.qsize = 0;
dev->crq.qnext = 0;
dprintf("CRQ for dev 0x" TARGET_FMT_lx " freed\n", reg);
return H_SUCCESS;
} }
static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr, static target_ulong h_send_crq(CPUPPCState *env, sPAPREnvironment *spapr,
@ -642,6 +648,15 @@ static int spapr_vio_check_reg(VIOsPAPRDevice *sdev)
return 0; 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) static int spapr_vio_busdev_init(DeviceState *qdev)
{ {
VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev; VIOsPAPRDevice *dev = (VIOsPAPRDevice *)qdev;
@ -670,6 +685,8 @@ static int spapr_vio_busdev_init(DeviceState *qdev)
rtce_init(dev); rtce_init(dev);
qemu_register_reset(spapr_vio_busdev_reset, dev);
return pc->init(dev); return pc->init(dev);
} }