From patchwork Wed Nov 21 14:46:05 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [3/3] s390/migration: Add code to support SCLP live migration X-Patchwork-Submitter: Christian Borntraeger X-Patchwork-Id: 200788 Message-Id: <1353509165-26865-4-git-send-email-borntraeger@de.ibm.com> To: Alexander Graf Cc: Christian Borntraeger , Jens Freimann , Heinz Graalfs , qemu-devel , "Jason J. herne" Date: Wed, 21 Nov 2012 15:46:05 +0100 From: Christian Borntraeger List-Id: From: Heinz Graalfs This patch adds the necessary life migration pieces to the sclp code. Signed-off-by: Heinz Graalfs Signed-off-by: Christian Borntraeger --- hw/s390x/event-facility.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ hw/s390x/event-facility.h | 3 +++ hw/s390x/sclpconsole.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ hw/s390x/sclpquiesce.c | 18 ++++++++++++++++++ 4 files changed, 113 insertions(+) diff --git a/hw/s390x/event-facility.c b/hw/s390x/event-facility.c index 9367660..47a1bab 100644 --- a/hw/s390x/event-facility.c +++ b/hw/s390x/event-facility.c @@ -312,6 +312,49 @@ static void command_handler(SCLPEventFacility *ef, SCCB *sccb, uint64_t code) } } +static void event_facility_save(QEMUFile *f, void *opaque) +{ + S390SCLPDevice *sdev = opaque; + BusChild *kid; + SCLPEvent *event; + SCLPEventClass *event_class; + + qemu_put_be32(f, sdev->ef->receive_mask); + + QTAILQ_FOREACH(kid, &sdev->ef->sbus.qbus.children, sibling) { + DeviceState *qdev = kid->child; + event = DO_UPCAST(SCLPEvent, qdev, qdev); + event_class = SCLP_EVENT_GET_CLASS(event); + if (event_class->save) { + event_class->save(f, event); + } + } +} + +static int event_facility_load(QEMUFile *f, void *opaque, int version_id) +{ + S390SCLPDevice *sdev = opaque; + int rc = 0; + BusChild *kid; + SCLPEvent *event; + SCLPEventClass *event_class; + + sdev->ef->receive_mask = qemu_get_be32(f); + + QTAILQ_FOREACH(kid, &sdev->ef->sbus.qbus.children, sibling) { + DeviceState *qdev = kid->child; + event = DO_UPCAST(SCLPEvent, qdev, qdev); + event_class = SCLP_EVENT_GET_CLASS(event); + if (event_class->load) { + rc = event_class->load(f, event, version_id); + if (rc) { + break; + } + } + } + return rc; +} + static int init_event_facility(S390SCLPDevice *sdev) { SCLPEventFacility *event_facility; @@ -334,6 +377,9 @@ static int init_event_facility(S390SCLPDevice *sdev) } qdev_init_nofail(quiesce); + register_savevm(&sdev->busdev.qdev, "event-facility", -1, 0, + event_facility_save, event_facility_load, sdev); + return 0; } diff --git a/hw/s390x/event-facility.h b/hw/s390x/event-facility.h index 30af0a7..4405022 100644 --- a/hw/s390x/event-facility.h +++ b/hw/s390x/event-facility.h @@ -91,6 +91,9 @@ typedef struct SCLPEventClass { /* returns the supported event type */ int (*event_type)(void); + /* live migration */ + int (*load)(QEMUFile *f, void *opaque, int version_id); + void (*save)(QEMUFile *f, void *opaque); } SCLPEventClass; #endif diff --git a/hw/s390x/sclpconsole.c b/hw/s390x/sclpconsole.c index 0ec5623..96168a1 100644 --- a/hw/s390x/sclpconsole.c +++ b/hw/s390x/sclpconsole.c @@ -243,6 +243,50 @@ static void trigger_ascii_console_data(void *env, int n, int level) /* qemu object creation and initialization functions */ /* tell character layer our call-back functions */ + +static void console_save(QEMUFile *f, void *opaque) +{ + SCLPConsole *scon = opaque; + + if (!scon->iov) { + return; + } + + qemu_put_be16(f, scon->event.event_pending ? 1 : 0); + qemu_put_be32(f, scon->iov_data_len); + qemu_put_be32(f, scon->iov_sclp_rest); + qemu_put_be32(f, scon->iov_sclp - scon->iov); + qemu_put_be32(f, scon->iov_bs - scon->iov); + if (scon->event.event_pending) { + qemu_put_buffer(f, scon->iov, SIZE_BUFFER_VT220); + } +} + +static int console_load(QEMUFile *f, void *opaque, int version_id) +{ + SCLPConsole *scon = opaque; + int l; + + if (!scon->iov) { + scon->iov = g_malloc0(SIZE_BUFFER_VT220); + } + + scon->event.event_pending = qemu_get_be16(f) ? true : false; + scon->iov_data_len = qemu_get_be32(f); + scon->iov_sclp_rest = qemu_get_be32(f); + scon->iov_bs = scon->iov + qemu_get_be32(f); + scon->iov_sclp = scon->iov + qemu_get_be32(f); + if (scon->event.event_pending) { + l = qemu_get_buffer(f, scon->iov, SIZE_BUFFER_VT220); + if (l != SIZE_BUFFER_VT220) { + error_report("Failed to restore SCLP console buffer."); + return -1; + } + } + + return 0; +} + static int console_init(SCLPEvent *event) { static bool console_available; @@ -288,6 +332,8 @@ static void console_class_init(ObjectClass *klass, void *data) ec->event_type = event_type; ec->read_event_data = read_event_data; ec->write_event_data = write_event_data; + ec->load = console_load; + ec->save = console_save; } static TypeInfo sclp_console_info = { diff --git a/hw/s390x/sclpquiesce.c b/hw/s390x/sclpquiesce.c index 9a773b8..e12fb7c 100644 --- a/hw/s390x/sclpquiesce.c +++ b/hw/s390x/sclpquiesce.c @@ -65,6 +65,22 @@ static int read_event_data(SCLPEvent *event, EventBufferHeader *evt_buf_hdr, return 1; } +static void quiesce_save(QEMUFile *f, void *opaque) +{ + SCLPEvent *event = opaque; + + qemu_put_be16(f, event->event_pending ? 1 : 0); +} + +static int quiesce_load(QEMUFile *f, void *opaque, int version_id) +{ + SCLPEvent *event = opaque; + + event->event_pending = qemu_get_be16(f) ? true : false; + + return 0; +} + typedef struct QuiesceNotifier QuiesceNotifier; static struct QuiesceNotifier { @@ -105,6 +121,8 @@ static void quiesce_class_init(ObjectClass *klass, void *data) k->event_type = event_type; k->read_event_data = read_event_data; k->write_event_data = NULL; + k->load = quiesce_load; + k->save = quiesce_save; } static TypeInfo sclp_quiesce_info = {