From: Alexander Graf <agraf@suse.de>
To: Jens Freimann <jfrei@de.ibm.com>
Cc: "Heinz Graalfs" <graalfs@linux.vnet.ibm.com>,
qemu-devel <qemu-devel@nongnu.org>,
"Christian Borntraeger" <borntraeger@de.ibm.com>,
"Jens Freimann" <jfrei@linux.vnet.ibm.com>,
"Cornelia Huck" <cornelia.huck@de.ibm.com>,
"Andreas Färber" <afaerber@suse.de>
Subject: Re: [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown
Date: Tue, 12 Jun 2012 13:38:07 +0200 [thread overview]
Message-ID: <4FD72A1F.2000903@suse.de> (raw)
In-Reply-To: <1338984323-21914-7-git-send-email-jfrei@de.ibm.com>
On 06/06/2012 02:05 PM, Jens Freimann wrote:
> From: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
>
> This patch implements a subset of the sclp event facility as well
> as the signal quiesce event. This allows to gracefully shutdown
> a guest by using system_powerdown. This sends a signal quiesce
> signal that is interpreted by linux guests as ctrl-alt-del.
> In addition the event facility is modeled using the QOM.
>
> Signed-off-by: Heinz Graalfs<graalfs@linux.vnet.ibm.com>
> Signed-off-by: Christian Borntraeger<borntraeger@de.ibm.com>
> Signed-off-by: Jens Freimann<jfrei@de.ibm.com>
Andreas, I'm always getting headaches reviewing qdev and/or qom patches.
Could you please check this for layering violations?
> ---
> Makefile.target | 1 +
> hw/s390-event-facility.c | 232 +++++++++++++++++++++++++++++++++++++++++
> hw/s390-event-facility.h | 54 ++++++++++
> hw/s390-sclp.c | 256 +++++++++++++++++++++++++++++++++++++++++++++-
> hw/s390-sclp.h | 98 +++++++++++++++++-
> hw/s390-virtio.c | 11 +-
> target-s390x/op_helper.c | 3 +
> 7 files changed, 649 insertions(+), 6 deletions(-)
> create mode 100644 hw/s390-event-facility.c
> create mode 100644 hw/s390-event-facility.h
>
> diff --git a/Makefile.target b/Makefile.target
> index fed2d72..f939c3a 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -375,6 +375,7 @@ obj-m68k-y = an5206.o mcf5206.o mcf_uart.o mcf_intc.o mcf5208.o mcf_fec.o
> obj-m68k-y += m68k-semi.o dummy_m68k.o
>
> obj-s390x-y = s390-virtio-bus.o s390-virtio.o s390-sclp.o
> +obj-s390x-y += s390-event-facility.o
>
> obj-alpha-y = mc146818rtc.o
> obj-alpha-y += alpha_pci.o alpha_dp264.o alpha_typhoon.o
> diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
> new file mode 100644
> index 0000000..b8106a6
> --- /dev/null
> +++ b/hw/s390-event-facility.c
> @@ -0,0 +1,232 @@
> +/*
> + * SCLP Event Facility
> + *
> + * Copyright IBM Corp. 2007,2012
> + * Author: Heinz Graalfs<graalfs@de.ibm.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License(GPL)
> + */
> +
> +#include "iov.h"
> +#include "monitor.h"
> +#include "qemu-queue.h"
> +#include "sysbus.h"
> +#include "sysemu.h"
> +
> +#include "s390-sclp.h"
> +#include "s390-event-facility.h"
> +
> +struct SCLPDevice {
> + const char *name;
> + bool vm_running;
> +};
> +
> +struct SCLP {
> + BusState qbus;
> + SCLPEventFacility *event_facility;
> +};
> +
> +struct SCLPEventFacility {
> + SCLPDevice sdev;
> + SCLP sbus;
> + DeviceState *qdev;
> + void *opaque;
> +};
> +
> +typedef struct SCLPConsole {
> + SCLPEvent event;
> + CharDriverState *chr;
> +} SCLPConsole;
> +
> +static void sclpef_bus_dev_print(Monitor *mon, DeviceState *qdev, int indent)
> +{
> + SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
> +
> + monitor_printf(mon, "%*sid %d\n", indent, "", event->id);
> +}
> +
> +static unsigned int send_mask_quiesce(void)
> +{
> + return SCLP_EVENT_MASK_SIGNAL_QUIESCE;
> +}
> +
> +static unsigned int receive_mask_quiesce(void)
> +{
> + return 0;
> +}
> +
> +static void s390_signal_quiesce(void *opaque, int n, int level)
> +{
> + sclp_enable_signal_quiesce();
> + sclp_service_interrupt(opaque, 0);
> +}
> +
> +unsigned int sclpef_send_mask(SCLPDevice *sdev)
> +{
> + unsigned int mask;
> + DeviceState *dev;
> + SCLPEventFacility *event_facility;
> + SCLPEventClass *cons;
> +
> + event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> +
> + mask = 0;
> +
> + QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> + cons = SCLP_EVENT_GET_CLASS((SCLPEvent *) dev);
> + mask |= cons->get_send_mask();
> + }
> + return mask;
> +}
> +
> +unsigned int sclpef_receive_mask(SCLPDevice *sdev)
> +{
> + unsigned int mask;
> + DeviceState *dev;
> + SCLPEventClass *cons;
> + SCLPEventFacility *event_facility;
> +
> + event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> +
> + mask = 0;
> +
> + QTAILQ_FOREACH(dev,&event_facility->sbus.qbus.children, sibling) {
> + cons = SCLP_EVENT_GET_CLASS((SCLPEvent *) dev);
> + mask |= cons->get_receive_mask();
> + }
> + return mask;
> +}
> +
> +static struct BusInfo sclp_bus_info = {
> + .name = "s390-sclp-bus",
> + .size = sizeof(SCLPS390Bus),
> + .print_dev = sclpef_bus_dev_print,
> + .props = (Property[]) {
> + DEFINE_PROP_STRING("name", SCLPEvent, name),
> + DEFINE_PROP_END_OF_LIST()
> + }
> +};
> +
> +static int sclpef_qdev_init(DeviceState *qdev)
> +{
> + int rc;
> + SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
> + SCLPEventClass *cons = SCLP_EVENT_GET_CLASS(event);
> + SCLP *bus = DO_UPCAST(SCLP, qbus, qdev->parent_bus);
> +
> + event->evt_fac = bus->event_facility;
> + rc = cons->init(event);
> +
> + return rc;
> +}
> +
> +static int sclpef_qdev_exit(DeviceState *qdev)
> +{
> + SCLPEvent *event = DO_UPCAST(SCLPEvent, dev, qdev);
> + SCLPEventClass *cons = SCLP_EVENT_GET_CLASS(event);
> + if (cons->exit) {
> + cons->exit(event);
> + }
> + return 0;
> +}
> +
> +static SCLPDevice *sclpef_common_init(const char *name, size_t struct_size)
> +{
> + SCLPDevice *sdev;
> +
> + sdev = malloc(struct_size);
g_malloc please. I suppose even g_malloc0?
> + if (!sdev) {
> + return NULL;
> + }
> + sdev->vm_running = runstate_is_running();
> + sdev->name = name;
> +
> + return sdev;
> +}
> +
> +void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque)
> +{
> + SCLPEventFacility *event_facility;
> +
> + event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> + qemu_system_powerdown = *qemu_allocate_irqs(s390_signal_quiesce,
> + opaque, 1);
> + event_facility->opaque = opaque;
> +}
> +
> +SCLPDevice *sclpef_init_event_facility(DeviceState *dev)
> +{
> + DeviceState *quiesce;
> + SCLPDevice *sdev;
> + SCLPEventFacility *event_facility;
> +
> + sdev = sclpef_common_init("sclp-event-facility",
> + sizeof(SCLPEventFacility));
> +
> + if (!sdev) {
> + return NULL;
> + }
> + event_facility = DO_UPCAST(SCLPEventFacility, sdev, sdev);
> +
> + /* Spawn a new sclp-facility */
> + qbus_create_inplace(&event_facility->sbus.qbus,&sclp_bus_info, dev, NULL);
> + event_facility->sbus.qbus.allow_hotplug = 0;
> + event_facility->sbus.event_facility = event_facility;
> + event_facility->qdev = dev;
> + event_facility->opaque = NULL;
> + quiesce = qdev_create(&event_facility->sbus.qbus, "sclpquiesce");
> +
> + if (!quiesce) {
> + return NULL;
> + }
> +
> + return sdev;
> +}
> +
> +static void sclpef_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + dc->init = sclpef_qdev_init;
> + dc->bus_info =&sclp_bus_info;
> + dc->exit = sclpef_qdev_exit;
> + dc->unplug = qdev_simple_unplug_cb;
> +}
> +
> +static TypeInfo sclp_event_facility_type_info = {
> + .name = TYPE_SCLP_EVENT,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(SCLPEvent),
> + .class_size = sizeof(SCLPEventClass),
> + .class_init = sclpef_class_init,
> + .abstract = true,
> +};
> +
> +static int sclpquiesce_initfn(SCLPEvent *event)
> +{
> + event->id = ID_QUIESCE;
> +
> + return 0;
> +}
> +
> +static void sclpef_quiesce_class_init(ObjectClass *klass, void *data)
> +{
> + SCLPEventClass *k = SCLP_EVENT_CLASS(klass);
> +
> + k->init = sclpquiesce_initfn;
> + k->get_send_mask = send_mask_quiesce;
> + k->get_receive_mask = receive_mask_quiesce;
> +}
> +
> +static TypeInfo sclp_quiesce_info = {
> + .name = "sclpquiesce",
> + .parent = TYPE_SCLP_EVENT,
> + .instance_size = sizeof(SCLPEvent),
> + .class_init = sclpef_quiesce_class_init,
> +};
> +
> +static void sclpef_register_types(void)
> +{
> + type_register_static(&sclp_event_facility_type_info);
> + type_register_static(&sclp_quiesce_info);
> +}
> +type_init(sclpef_register_types)
> diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
> new file mode 100644
> index 0000000..40d4049
> --- /dev/null
> +++ b/hw/s390-event-facility.h
> @@ -0,0 +1,54 @@
> +/*
> + * SCLP definitions
> + *
> + * Copyright IBM Corp. 2007,2012
> + * Author: Heinz Graalfs<graalfs@de.ibm.com>
> + *
> + * This file is licensed under the terms of the GNU General Public License(GPL)
> + */
> +
> +#ifndef _QEMU_SCLP_EVENT_H
> +#define _QEMU_SCLP_EVENT_H
> +
> +#include "qdev.h"
> +#include "qemu-common.h"
> +
> +#define ID_QUIESCE SCLP_EVENT_SIGNAL_QUIESCE
> +
> +#define TYPE_SCLP_EVENT "s390-sclp-event-type"
> +#define SCLP_EVENT(obj) \
> + OBJECT_CHECK(SCLPEvent, (obj), TYPE_SCLP_EVENT)
> +#define SCLP_EVENT_CLASS(klass) \
> + OBJECT_CLASS_CHECK(SCLPEventClass, (klass), TYPE_SCLP_EVENT)
> +#define SCLP_EVENT_GET_CLASS(obj) \
> + OBJECT_GET_CLASS(SCLPEventClass, (obj), TYPE_SCLP_EVENT)
> +
> +typedef struct SCLP SCLP;
> +typedef struct SCLPEventFacility SCLPEventFacility;
> +typedef struct SCLPEvent SCLPEvent;
> +typedef struct SCLPDevice SCLPDevice;
> +
> +typedef struct SCLPEventClass {
> + DeviceClass parent_class;
> + int (*init)(SCLPEvent *event);
> + int (*exit)(SCLPEvent *event);
> + unsigned int (*get_send_mask)(void);
> + unsigned int (*get_receive_mask)(void);
> +} SCLPEventClass;
> +
> +struct SCLPEvent {
> + DeviceState dev;
> + SCLPEventFacility *evt_fac;
> + char *name;
> + uint32_t id;
> +};
> +
> +SCLPDevice *sclpef_init_event_facility(DeviceState *dev);
> +
> +void sclpef_enable_irqs(SCLPDevice *sdev, void *opaque);
> +
> +void sclpef_set_masks(void);
> +unsigned int sclpef_send_mask(SCLPDevice *sdev);
> +unsigned int sclpef_receive_mask(SCLPDevice *sdev);
> +
> +#endif
> diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> index c046441..683a709 100644
> --- a/hw/s390-sclp.c
> +++ b/hw/s390-sclp.c
> @@ -7,7 +7,20 @@
>
> #include "cpu.h"
> #include "kvm.h"
> +#include "hw/sysbus.h"
> #include "hw/s390-sclp.h"
> +#include "hw/s390-event-facility.h"
> +
> +/* Host capabilites */
> +static unsigned int sclp_send_mask;
> +static unsigned int sclp_receive_mask;
> +
> +/* Guest capabilities */
> +static unsigned int sclp_cp_send_mask;
> +static unsigned int sclp_cp_receive_mask;
> +
> +static int quiesce;
> +static int event_pending;
Global variables? Bad idea :). These should be properties of your
quiesce device.
>
> int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
> {
> @@ -23,20 +36,257 @@ int sclp_read_info(CPUS390XState *env, struct sccb *sccb)
> return 0;
> }
>
> +static int signal_quiesce_event(struct sccb *sccb, int *slen)
> +{
> + if (!quiesce) {
> + return 0;
> + }
> +
> + if (*slen< sizeof(struct signal_quiesce)) {
> + event_pending = 1;
> + return 0;
> + }
> +
> + sccb->c.read.quiesce.h.length = cpu_to_be16(sizeof(struct signal_quiesce));
> + sccb->c.read.quiesce.h.type = SCLP_EVENT_SIGNAL_QUIESCE;
> + sccb->c.read.quiesce.h.flags&= ~SCLP_EVENT_BUFFER_ACCEPTED;
> + /*
> + * system_powerdown does not have a timeout. Fortunately the
> + * timeout value is curently ignored by Linux, anyway
> + */
> + sccb->c.read.quiesce.timeout = cpu_to_be16(0);
> + sccb->c.read.quiesce.unit = cpu_to_be16(0);
> +
> + quiesce = 0;
> + *slen -= sizeof(struct signal_quiesce);
> + return 1;
> +}
> +
> +void sclp_enable_signal_quiesce(void)
> +{
> + quiesce = 1;
> + event_pending = 1;
> +}
> +
> +static void sclp_set_masks(void)
> +{
> + SCLPS390EventFacility *evt_fac;
> +
> + if (!sclp_bus) {
> + return;
> + }
> + evt_fac = sclp_bus->event_facility;
> +
> + assert(evt_fac);
> +
> + sclp_send_mask = sclpef_send_mask(evt_fac->sdev);
> + sclp_receive_mask = sclpef_receive_mask(evt_fac->sdev);
> + }
> +
> +int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb)
> +{
> + unsigned int sclp_active_selection_mask;
> + int slen;
> +
> + if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) {
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
> + goto out;
> + }
> +
> + switch (sccb->h.function_code) {
> + case SCLP_UNCONDITIONAL_READ:
> + sclp_active_selection_mask = sclp_cp_receive_mask;
> + break;
> + case SCLP_SELECTIVE_READ:
> + if (!(sclp_cp_receive_mask& be32_to_cpu(sccb->c.read.mask))) {
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
> + goto out;
> + }
> + sclp_active_selection_mask = be32_to_cpu(sccb->c.read.mask);
> + break;
> + default:
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
> + goto out;
> + }
> +
> + slen = sizeof(sccb->c.data);
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_NO_EVENT_BUFFERS_STORED);
> +
> + if (sclp_active_selection_mask& SCLP_EVENT_MASK_SIGNAL_QUIESCE) {
> + if (signal_quiesce_event(sccb,&slen)) {
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> + }
> + }
> +
> + if (sccb->h.control_mask[2]& SCLP_VARIABLE_LENGTH_RESPONSE) {
> + sccb->h.control_mask[2]&= ~SCLP_VARIABLE_LENGTH_RESPONSE;
> + sccb->h.length = cpu_to_be16(SCCB_SIZE - slen);
> + }
> +
> +out:
> + return 0;
> +}
> +
> +int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb)
> +{
> + /* Attention: We assume that Linux uses 4-byte masks, what it actually
> + does. Architecture allows for masks of variable size, though */
> + if (be16_to_cpu(sccb->c.we_mask.mask_length) != 4) {
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_MASK_LENGTH);
> + goto out;
> + }
> +
> + /* keep track of the guest's capability masks */
> + sclp_cp_send_mask = be32_to_cpu(sccb->c.we_mask.cp_send_mask);
> + sclp_cp_receive_mask = be32_to_cpu(sccb->c.we_mask.cp_receive_mask);
> +
> + sclp_set_masks();
> +
> + /* return the SCLP's capability masks to the guest */
> + sccb->c.we_mask.send_mask = cpu_to_be32(sclp_send_mask);
> + sccb->c.we_mask.receive_mask = cpu_to_be32(sclp_receive_mask);
> +
> + sccb->h.response_code = cpu_to_be32(SCLP_RC_NORMAL_COMPLETION);
> +
> +out:
> + return 0;
> +}
> +
> void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb)
> {
> - if (!sccb) {
> + if (!event_pending&& !sccb) {
> return;
> }
>
> if (kvm_enabled()) {
> #ifdef CONFIG_KVM
> kvm_s390_interrupt_internal(env, KVM_S390_INT_SERVICE,
> - (sccb& ~3), 0, 1);
> + (sccb& ~3) + event_pending, 0, 1);
> #endif
> } else {
> env->psw.addr += 4;
> - cpu_inject_ext(env, EXT_SERVICE, (sccb& ~3), 0);
> + cpu_inject_ext(env, EXT_SERVICE, (sccb& ~3) + event_pending, 0);
> + }
Please fix the above piece of code to use the same mechanism regarless
of TCG or KVM, so that SCLP code doesn't have to be aware of KVM.
> + event_pending = 0;
> +}
> +
> +struct BusInfo s390_sclp_bus_info = {
> + .name = "s390-sclp",
> + .size = sizeof(SCLPS390Bus),
> +};
> +
> +SCLPS390Bus *s390_sclp_bus_init(void)
> +{
> + SCLPS390Bus *bus;
> + BusState *bus_state;
> + DeviceState *dev;
> +
> + dev = qdev_create(NULL, "s390-sclp-bridge");
> + qdev_init_nofail(dev);
> + bus_state = qbus_create(&s390_sclp_bus_info, dev, "s390-sclp-bus");
> + bus = DO_UPCAST(SCLPS390Bus, bus, bus_state);
> +
> + bus_state->allow_hotplug = 0;
> +
> + return bus;
> +}
> +
> +static int s390_sclp_device_init(SCLPS390EventFacility *dev, SCLPDevice *sdev)
> +{
> + dev->sdev = sdev;
> +
> + return 0;
> +}
> +
> +static int s390_sclp_init(SCLPS390EventFacility *dev)
> +{
> + int rc;
> + SCLPS390Bus *bus;
> + SCLPDevice *sdev;
> +
> + bus = DO_UPCAST(SCLPS390Bus, bus, dev->qdev.parent_bus);
> +
> + sdev = sclpef_init_event_facility((DeviceState *)dev);
> + if (!sdev) {
> + return -1;
> }
> +
> + rc = s390_sclp_device_init(dev, sdev);
> + if (!rc) {
> + bus->event_facility = dev;
> + }
> +
> + return rc;
> +}
> +
> +static void s390_sclp_class_init(ObjectClass *klass, void *data)
> +{
> + SCLPS390EventFacilityClass *k = SCLP_S390_EVENT_FACILITY_CLASS(klass);
> +
> + k->init = s390_sclp_init;
> +}
> +
> +static TypeInfo s390_sclp_event_facility = {
> + .name = "sclp-event-facility",
> + .parent = TYPE_SCLP_S390_EVENT_FACILITY,
> + .instance_size = sizeof(SCLPS390EventFacility),
> + .class_init = s390_sclp_class_init,
> +};
> +
> +static int s390_sclp_busdev_init(DeviceState *dev)
> +{
> + SCLPS390EventFacility *_dev = (SCLPS390EventFacility *)dev;
> + SCLPS390EventFacilityClass *evt_fac =
> + SCLP_S390_EVENT_FACILITY_GET_CLASS(dev);
> +
> + return evt_fac->init(_dev);
> }
>
> +static void sclp_s390_device_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->init = s390_sclp_busdev_init;
> + dc->bus_info =&s390_sclp_bus_info;
> +}
> +
> +static TypeInfo sclp_s390_device_info = {
> + .name = TYPE_SCLP_S390_EVENT_FACILITY,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(SCLPS390EventFacility),
> + .class_init = sclp_s390_device_class_init,
> + .class_size = sizeof(SCLPS390EventFacilityClass),
> + .abstract = true,
> +};
> +
> +/***************** S390 SCLP Bus Bridge Device *******************/
> +/* Only required to have the sclp bus as child in the system bus */
> +
> +static int s390_sclp_bridge_init(SysBusDevice *dev)
> +{
> + return 0;
> +}
> +
> +static void s390_sclp_bridge_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
> +
> + k->init = s390_sclp_bridge_init;
> + dc->no_user = 1;
> +}
> +
> +static TypeInfo s390_sclp_bridge_info = {
> + .name = "s390-sclp-bridge",
> + .parent = TYPE_SYS_BUS_DEVICE,
> + .instance_size = sizeof(SysBusDevice),
> + .class_init = s390_sclp_bridge_class_init,
> +};
> +
> +static void s390_sclp_register_types(void)
> +{
> + type_register_static(&sclp_s390_device_info);
> + type_register_static(&s390_sclp_event_facility);
> + type_register_static(&s390_sclp_bridge_info);
> +}
> +type_init(s390_sclp_register_types)
> diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
> index e335b21..f61421b 100644
> --- a/hw/s390-sclp.h
> +++ b/hw/s390-sclp.h
> @@ -1,13 +1,69 @@
> #include<stdint.h>
> #include<qemu-common.h>
>
> +#include "sysbus.h"
> +#include "hw/s390-event-facility.h"
>
> /* SCLP command codes */
> #define SCLP_CMDW_READ_SCP_INFO 0x00020001
> #define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
> +#define SCLP_CMD_WRITE_EVENT_MASK 0x00780005
>
> /* SCLP response codes */
> -#define SCLP_RC_SCCB_RESOURCE_INSUFFICENT 0x07f0
> +#define SCLP_RC_NORMAL_COMPLETION 0x0020
> +#define SCLP_RC_INSUFFICIENT_SCCB_LENGTH 0x0300
> +#define SCLP_RC_INVALID_FUNCTION 0x40f0
> +#define SCLP_RC_NO_EVENT_BUFFERS_STORED 0x60f0
> +#define SCLP_RC_INVALID_SELECTION_MASK 0x70f0
> +#define SCLP_RC_INCONSISTENT_LENGTHS 0x72f0
> +#define SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR 0x73f0
> +#define SCLP_RC_INVALID_MASK_LENGTH 0x74f0
> +
> +/* SCLP event types */
> +#define SCLP_EVENT_SIGNAL_QUIESCE 0x1d
> +
> +/* SCLP event masks */
> +#define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008
> +#define SCLP_EVENT_MASK_MSG 0x40000000
> +
> +#define SCLP_UNCONDITIONAL_READ 0x00
> +#define SCLP_SELECTIVE_READ 0x01
> +
> +#define SCLP_VARIABLE_LENGTH_RESPONSE 0x80
> +
> +#define SCCB_SIZE 4096
> +
> +/* Service Call Control Block (SCCB) and its elements */
> +
> +struct write_event_mask {
> + uint16_t _reserved;
> + uint16_t mask_length;
> + uint32_t cp_receive_mask;
> + uint32_t cp_send_mask;
> + uint32_t send_mask;
> + uint32_t receive_mask;
> +} __attribute__((packed));
> +
> +struct event_buffer_header {
> + uint16_t length;
> + uint8_t type;
> +#define SCLP_EVENT_BUFFER_ACCEPTED 0x80
> + uint8_t flags;
> + uint16_t _reserved;
> +} __attribute__((packed));
> +
> +struct signal_quiesce {
> + struct event_buffer_header h;
> + uint16_t timeout;
> + uint8_t unit;
> +} __attribute__((packed));
> +
> +struct read_event_data {
> + union {
> + struct signal_quiesce quiesce;
> + uint32_t mask;
> + };
> +} __attribute__((packed));
>
> struct sccb_header {
> uint16_t length;
> @@ -22,13 +78,51 @@ struct read_info_sccb {
> uint8_t rnsize;
> } __attribute__((packed));
>
> +#define SCCB_DATA_LEN 4088
> +
> struct sccb {
> struct sccb_header h;
> union {
> struct read_info_sccb read_info;
> - char data[4088];
> + struct read_event_data read;
> + struct write_event_mask we_mask;
> + char data[SCCB_DATA_LEN];
> } c;
> } __attribute__((packed));
>
> +void sclp_enable_signal_quiesce(void);
> int sclp_read_info(CPUS390XState *env, struct sccb *sccb);
> +int sclp_read_event_data(CPUS390XState *env, struct sccb *sccb);
> +int sclp_write_event_mask(CPUS390XState *env, struct sccb *sccb);
> void sclp_service_interrupt(CPUS390XState *env, uint32_t sccb);
> +
> +#define TYPE_SCLP_S390_EVENT_FACILITY "s390-sclp-event-facility"
> +#define SCLP_S390_EVENT_FACILITY(obj) \
> + OBJECT_CHECK(SCLPS390EventFacility, (obj), TYPE_SCLP_S390_EVENT_FACILITY)
> +#define SCLP_S390_EVENT_FACILITY_CLASS(klass) \
> + OBJECT_CLASS_CHECK(SCLPS390EventFacilityClass, (klass), \
> + TYPE_SCLP_S390_EVENT_FACILITY)
> +#define SCLP_S390_EVENT_FACILITY_GET_CLASS(obj) \
> + OBJECT_GET_CLASS(SCLPS390EventFacilityClass, (obj), \
> + TYPE_SCLP_S390_EVENT_FACILITY)
> +
> +typedef struct SCLPS390EventFacility SCLPS390EventFacility;
> +
> +typedef struct SCLPS390EventFacilityClass {
> + DeviceClass qdev;
> + int (*init)(SCLPS390EventFacility *dev);
> +} SCLPS390EventFacilityClass;
> +
> +struct SCLPS390EventFacility {
> + DeviceState qdev;
> + SCLPDevice *sdev;
> +};
> +
> +typedef struct SCLPS390Bus {
> + BusState bus;
> + SCLPS390EventFacility *event_facility;
> +} SCLPS390Bus;
> +
> +extern SCLPS390Bus *sclp_bus;
> +
> +SCLPS390Bus *s390_sclp_bus_init(void);
> diff --git a/hw/s390-virtio.c b/hw/s390-virtio.c
> index c0e19fd..0babf27 100644
> --- a/hw/s390-virtio.c
> +++ b/hw/s390-virtio.c
> @@ -32,6 +32,7 @@
> #include "exec-memory.h"
>
> #include "hw/s390-virtio-bus.h"
> +#include "hw/s390-sclp.h"
>
> //#define DEBUG_S390
>
> @@ -60,7 +61,9 @@
>
> #define MAX_BLK_DEVS 10
>
> -static VirtIOS390Bus *s390_bus;
> +VirtIOS390Bus *s390_bus;
> +SCLPS390Bus *sclp_bus;
> +
> static CPUS390XState **ipi_states;
>
> CPUS390XState *s390_cpu_addr2state(uint16_t cpu_addr)
> @@ -170,6 +173,7 @@ static void s390_init(ram_addr_t my_ram_size,
> target_phys_addr_t virtio_region_len;
> target_phys_addr_t virtio_region_start;
> int i;
> + DeviceState *dev;
>
> /* s390x ram size detection needs a 16bit multiplier + an increment. So
> guests> 64GB can be specified in 2MB steps etc. */
> @@ -183,6 +187,7 @@ static void s390_init(ram_addr_t my_ram_size,
>
> /* get a BUS */
> s390_bus = s390_virtio_bus_init(&my_ram_size);
> + sclp_bus = s390_sclp_bus_init();
>
> /* allocate RAM */
> memory_region_init_ram(ram, "s390.ram", my_ram_size);
> @@ -325,6 +330,10 @@ static void s390_init(ram_addr_t my_ram_size,
> qdev_prop_set_drive_nofail(dev, "drive", dinfo->bdrv);
> qdev_init_nofail(dev);
> }
> +
> + dev = qdev_create((BusState *)sclp_bus, "sclp-event-facility");
> + qdev_init_nofail(dev);
> + sclpef_enable_irqs(sclp_bus->event_facility->sdev, ipi_states[0]);
> }
>
> static QEMUMachine s390_machine = {
> diff --git a/target-s390x/op_helper.c b/target-s390x/op_helper.c
> index 74bd9ad..3e5eff4 100644
> --- a/target-s390x/op_helper.c
> +++ b/target-s390x/op_helper.c
> @@ -2391,6 +2391,9 @@ int sclp_service_call(CPUS390XState *env, uint32_t sccb, uint64_t code)
> case SCLP_CMDW_READ_SCP_INFO_FORCED:
> r = sclp_read_info(env,&work_sccb);
> break;
> + case SCLP_CMD_WRITE_EVENT_MASK:
> + r = sclp_write_event_mask(env,&work_sccb);
> + break;
> default:
I don't understand most of the patch tbh. It does a lot of things at the
same time, but none of them really thorough. Please split this off into
separate patches and make them actually do something small, but
constistently.
Things I saw while looking over this:
- you create a bus to plug in sclp users. This needs to be separate.
Don't introduce users of a framework when introducing the framework
itself, unless really neccessary (or if the patch only becomes 5 lines
longer)
- you create objects for the new event parser, but not all the other
sclp users. There's also no generic distribution mechanism in place
- the event parser itself uses globals - that's nowhere near object
oriented :)
- I don't see the header inclusions i commented on in the last patch
remedied here, please think your model over. In general, moving sclp to
hw/ is probably a good idea, but then please do it in a properly
abstracted way.
- A lot of the above code could use some comments, so people reading
it would actually understand what's going on :)
Alex
next prev parent reply other threads:[~2012-06-12 11:38 UTC|newest]
Thread overview: 51+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-06-06 12:05 [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Jens Freimann
2012-06-06 12:05 ` [Qemu-devel] [PATCH 1/8] s390: add new define for KVM_CAP_S390_COW Jens Freimann
2012-06-06 12:05 ` [Qemu-devel] [PATCH 2/8] s390: autodetect map private Jens Freimann
2012-06-12 9:32 ` Alexander Graf
2012-06-12 11:20 ` Christian Borntraeger
2012-06-12 11:57 ` Alexander Graf
2012-06-12 12:02 ` Christian Borntraeger
2012-06-12 12:12 ` Alexander Graf
2012-06-13 10:30 ` Jan Kiszka
2012-06-13 10:54 ` Alexander Graf
2012-06-13 10:58 ` Jan Kiszka
2012-06-13 11:27 ` Christian Borntraeger
2012-06-13 11:41 ` Jan Kiszka
2012-06-13 12:33 ` Alexander Graf
2012-06-13 12:35 ` Jan Kiszka
2012-06-15 14:01 ` [Qemu-devel] Next version of memory allocation fixup Christian Borntraeger
2012-06-15 14:01 ` [Qemu-devel] [PatchV2] s390: autodetect map private Christian Borntraeger
2012-06-15 15:10 ` [Qemu-devel] One more fix Christian Borntraeger
2012-06-15 15:10 ` [Qemu-devel] [PATCH v3] s390: autodetect map private Christian Borntraeger
2012-06-15 17:01 ` Jan Kiszka
2012-06-18 13:44 ` Alexander Graf
2012-06-06 12:05 ` [Qemu-devel] [PATCH 3/8] s390: make kvm_stat work on s390 Jens Freimann
2012-06-06 12:05 ` [Qemu-devel] [PATCH 4/8] s390: stop target cpu on sigp initial reset Jens Freimann
2012-06-12 9:42 ` Alexander Graf
2012-06-12 10:15 ` Christian Borntraeger
2012-06-06 12:05 ` [Qemu-devel] [PATCH 5/8] s390: Cleanup sclp functions Jens Freimann
2012-06-12 9:58 ` Alexander Graf
2012-06-12 10:07 ` Christian Borntraeger
2012-06-12 10:09 ` Alexander Graf
2012-06-12 10:10 ` Alexander Graf
2012-06-12 12:24 ` Christian Borntraeger
2012-06-12 12:32 ` Alexander Graf
2012-06-12 22:41 ` Anthony Liguori
2012-06-12 22:38 ` Anthony Liguori
2012-06-06 12:05 ` [Qemu-devel] [PATCH 6/8] s390: sclp event facility and signal quiesce support via system_powerdown Jens Freimann
2012-06-12 11:38 ` Alexander Graf [this message]
2012-06-13 7:00 ` Heinz Graalfs
2012-06-13 13:12 ` Andreas Färber
2012-06-06 12:05 ` [Qemu-devel] [PATCH 7/8] s390: Add SCLP vt220 console support Jens Freimann
2012-06-12 11:52 ` Alexander Graf
2012-06-13 7:27 ` Heinz Graalfs
2012-06-13 7:53 ` Alexander Graf
2012-06-06 12:05 ` [Qemu-devel] [PATCH 8/8] s390: Fix the storage increment size calculation Jens Freimann
2012-06-12 11:53 ` Alexander Graf
2012-06-12 14:57 ` Jeng-fang Wang
2012-06-18 13:46 ` Alexander Graf
2012-06-18 19:30 ` Christian Borntraeger
2012-06-18 12:35 ` [Qemu-devel] [PATCH 0/8] s390: SCLP console and misc Christian Borntraeger
2012-06-18 13:33 ` Alexander Graf
2012-06-18 13:41 ` Christian Borntraeger
2012-06-18 13:51 ` Alexander Graf
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4FD72A1F.2000903@suse.de \
--to=agraf@suse.de \
--cc=afaerber@suse.de \
--cc=borntraeger@de.ibm.com \
--cc=cornelia.huck@de.ibm.com \
--cc=graalfs@linux.vnet.ibm.com \
--cc=jfrei@de.ibm.com \
--cc=jfrei@linux.vnet.ibm.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.