s390x/pci: make hot-unplug handler smoother
The current implementation of hot-unplug handler is abrupt. Any pci operation will be just rejected if pci device is unconfigured. Thus a pci device can not be reset or destroyed in a right, smooth and safe way. Improve this as follows: - Notify the guest via a HP_EVENT_DECONFIGURE_REQUEST(0x303) event in the unplug handler, giving it a chance to deconfigure the device via sclp and allowing us to continue hot-unplug afterwards. - Set up a timer that will generate the HP_EVENT_CONFIGURE_TO_STBRES (0x304) event as before if the guest did not react after an adequate time. Signed-off-by: Yi Min Zhao <zyimin@linux.vnet.ibm.com> Reviewed-by: Pierre Morel <pmorel@linux.vnet.ibm.com> Signed-off-by: Cornelia Huck <cornelia.huck@de.ibm.com>
This commit is contained in:
parent
cdd85eb280
commit
93d16d81c8
@ -192,6 +192,10 @@ void s390_pci_sclp_deconfigure(SCCB *sccb)
|
||||
}
|
||||
pbdev->state = ZPCI_FS_STANDBY;
|
||||
rc = SCLP_RC_NORMAL_COMPLETION;
|
||||
|
||||
if (pbdev->release_timer) {
|
||||
qdev_unplug(DEVICE(pbdev->pdev), NULL);
|
||||
}
|
||||
}
|
||||
out:
|
||||
psccb->header.response_code = cpu_to_be16(rc);
|
||||
@ -679,6 +683,23 @@ static void s390_pcihost_hot_plug(HotplugHandler *hotplug_dev,
|
||||
}
|
||||
}
|
||||
|
||||
static void s390_pcihost_timer_cb(void *opaque)
|
||||
{
|
||||
S390PCIBusDevice *pbdev = opaque;
|
||||
|
||||
if (pbdev->summary_ind) {
|
||||
pci_dereg_irqs(pbdev);
|
||||
}
|
||||
if (pbdev->iommu_enabled) {
|
||||
pci_dereg_ioat(pbdev);
|
||||
}
|
||||
|
||||
pbdev->state = ZPCI_FS_STANDBY;
|
||||
s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES,
|
||||
pbdev->fh, pbdev->fid);
|
||||
qdev_unplug(DEVICE(pbdev), NULL);
|
||||
}
|
||||
|
||||
static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
|
||||
DeviceState *dev, Error **errp)
|
||||
{
|
||||
@ -712,8 +733,20 @@ static void s390_pcihost_hot_unplug(HotplugHandler *hotplug_dev,
|
||||
case ZPCI_FS_STANDBY:
|
||||
break;
|
||||
default:
|
||||
s390_pci_generate_plug_event(HP_EVENT_CONFIGURED_TO_STBRES,
|
||||
s390_pci_generate_plug_event(HP_EVENT_DECONFIGURE_REQUEST,
|
||||
pbdev->fh, pbdev->fid);
|
||||
pbdev->release_timer = timer_new_ns(QEMU_CLOCK_VIRTUAL,
|
||||
s390_pcihost_timer_cb,
|
||||
pbdev);
|
||||
timer_mod(pbdev->release_timer,
|
||||
qemu_clock_get_ns(QEMU_CLOCK_VIRTUAL) + HOT_UNPLUG_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (pbdev->release_timer && timer_pending(pbdev->release_timer)) {
|
||||
timer_del(pbdev->release_timer);
|
||||
timer_free(pbdev->release_timer);
|
||||
pbdev->release_timer = NULL;
|
||||
}
|
||||
|
||||
s390_pci_generate_plug_event(HP_EVENT_STANDBY_TO_RESERVED,
|
||||
|
@ -34,6 +34,7 @@
|
||||
#define ZPCI_MAX_UID 0xffff
|
||||
#define UID_UNDEFINED 0
|
||||
#define UID_CHECKING_ENABLED 0x01
|
||||
#define HOT_UNPLUG_TIMEOUT (NANOSECONDS_PER_SECOND * 60 * 5)
|
||||
|
||||
#define S390_PCI_HOST_BRIDGE(obj) \
|
||||
OBJECT_CHECK(S390pciState, (obj), TYPE_S390_PCI_HOST_BRIDGE)
|
||||
@ -44,6 +45,7 @@
|
||||
|
||||
#define HP_EVENT_TO_CONFIGURED 0x0301
|
||||
#define HP_EVENT_RESERVED_TO_STANDBY 0x0302
|
||||
#define HP_EVENT_DECONFIGURE_REQUEST 0x0303
|
||||
#define HP_EVENT_CONFIGURED_TO_STBRES 0x0304
|
||||
#define HP_EVENT_STANDBY_TO_RESERVED 0x0308
|
||||
|
||||
@ -283,6 +285,7 @@ typedef struct S390PCIBusDevice {
|
||||
MemoryRegion iommu_mr;
|
||||
IndAddr *summary_ind;
|
||||
IndAddr *indicator;
|
||||
QEMUTimer *release_timer;
|
||||
} S390PCIBusDevice;
|
||||
|
||||
typedef struct S390PCIBus {
|
||||
|
Loading…
Reference in New Issue
Block a user