[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 3/6] s390: sclp event support
From: |
Blue Swirl |
Subject: |
Re: [Qemu-devel] [PATCH 3/6] s390: sclp event support |
Date: |
Fri, 13 Jul 2012 15:10:51 +0000 |
On Fri, Jul 13, 2012 at 10:52 AM, Christian Borntraeger
<address@hidden> wrote:
> From: Heinz Graalfs <address@hidden>
>
> Several SCLP features are considered to be events. Those events don't
> provide SCLP commands on their own, instead they are all based on
> Read Event Data, Write Event Data, Write Event Mask and the service
> interrupt. Follow-on patches will provide SCLP's Signal Quiesce (via
> system_powerdown) and the ASCII console.
> Further down the road the sclp line mode console and configuration
> change events (e.g. cpu hotplug) can be implemented.
>
> Signed-off-by: Heinz Graalfs <address@hidden>
> Signed-off-by: Christian Borntraeger <address@hidden>
> ---
> hw/s390-event-facility.c | 412
> ++++++++++++++++++++++++++++++++++++++++++++++
> hw/s390-event-facility.h | 107 ++++++++++++
> hw/s390-sclp.c | 49 +++++-
> hw/s390-sclp.h | 43 +++++
> hw/s390x/Makefile.objs | 2 +-
> 5 files changed, 606 insertions(+), 7 deletions(-)
> create mode 100644 hw/s390-event-facility.c
> create mode 100644 hw/s390-event-facility.h
>
> diff --git a/hw/s390-event-facility.c b/hw/s390-event-facility.c
> new file mode 100644
> index 0000000..42ac102
> --- /dev/null
> +++ b/hw/s390-event-facility.c
> @@ -0,0 +1,412 @@
> +/*
> + * SCLP
> + * Event Facility
> + * handles SCLP event types
> + * - Signal Quiesce - system power down
> + * - ASCII Console Data - VT220 read and write
> + *
> + * Copyright IBM, Corp. 2007, 2012
> + *
> + * Authors:
> + * Heinz Graalfs <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +
> +#include "monitor.h"
> +#include "sysemu.h"
> +
> +#include "s390-sclp.h"
> +#include "s390-event-facility.h"
> +
> +typedef struct EventTypes {
> + BusState qbus;
> + SCLPEventFacility *event_facility;
> +} EventTypes;
> +
> +struct SCLPEventFacility {
> + EventTypes sbus;
> + DeviceState *qdev;
> + /* guest' receive mask */
> + unsigned int receive_mask;
> +};
> +
> +/* return true if any child has event pending set */
> +static bool event_pending(void)
> +{
> + BusChild *kid;
> + SCLPEvent *event;
> +
> + SCLPEventFacility *event_facility = sclp_bus->event_facility->instance;
> +
> + QTAILQ_FOREACH(kid, &event_facility->sbus.qbus.children, sibling) {
> + DeviceState *qdev = kid->child;
> + event = DO_UPCAST(SCLPEvent, qdev, qdev);
> + lock(event);
> + if (event->event_pending) {
> + unlock(event);
> + return true;
> + }
> + unlock(event);
> + }
> + return false;
> +}
> +
> +static unsigned int get_host_send_mask(void)
> +{
> + unsigned int mask;
> + BusChild *kid;
> + SCLPEventClass *child;
> + SCLPEventFacility *event_facility = sclp_bus->event_facility->instance;
> +
> + mask = 0;
> +
> + QTAILQ_FOREACH(kid, &event_facility->sbus.qbus.children, sibling) {
> + DeviceState *qdev = kid->child;
> + child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev);
> + mask |= child->get_send_mask();
> + }
> + return mask;
> +}
> +
> +static unsigned int get_host_receive_mask(void)
> +{
> + unsigned int mask;
> + BusChild *kid;
> + SCLPEventClass *child;
> + SCLPEventFacility *event_facility = sclp_bus->event_facility->instance;
> +
> + mask = 0;
> +
> + QTAILQ_FOREACH(kid, &event_facility->sbus.qbus.children, sibling) {
> + DeviceState *qdev = kid->child;
> + child = SCLP_EVENT_GET_CLASS((SCLPEvent *) qdev);
> + mask |= child->get_receive_mask();
> + }
> + return mask;
> +}
> +
> +static inline void set_guest_receive_mask(unsigned int mask)
> +{
> + SCLPEventFacility *event_facility = sclp_bus->event_facility->instance;
> +
> + event_facility->receive_mask = mask;
> +}
> +
> +static inline unsigned int get_guest_receive_mask(void)
> +{
> + SCLPEventFacility *event_facility = sclp_bus->event_facility->instance;
> +
> + return event_facility->receive_mask;
> +}
> +
> +static int check_sccb_events(SCCB *sccb)
bool? This returns only 0 or 1.
> +{
> + int slen;
> + unsigned elen = 0;
> + EventBufferHeader *event;
> + WriteEventData *wed = (WriteEventData *) sccb;
> +
> + event = (EventBufferHeader *) &wed->ebh;
> + for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
> + slen > 0; slen -= elen) {
> + elen = be16_to_cpu(event->length);
> + if (elen < sizeof(*event) || elen > slen) {
> + sccb->h.response_code =
> + cpu_to_be16(SCLP_RC_EVENT_BUFFER_SYNTAX_ERROR);
> + return 1;
> + }
> + event = (void *) event + elen;
> + }
> + if (slen) {
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INCONSISTENT_LENGTHS);
> + return 1;
> + }
> + return 0;
> +}
> +
> +static void handle_sccb_write_events(SCCB *sccb)
> +{
> + int slen;
> + unsigned elen = 0;
> + EventBufferHeader *event_buf;
> + BusChild *kid;
> + SCLPEvent *event;
> + SCLPEventClass *ec;
> +
> + WriteEventData *wed = (WriteEventData *) sccb;
> +
> + SCLPEventFacility *event_facility = sclp_bus->event_facility->instance;
> +
> + event_buf = &wed->ebh;
> +
> + /* loop over all contained event buffers */
> + for (slen = be16_to_cpu(sccb->h.length) - sizeof(sccb->h);
> + slen > 0; slen -= elen) {
> + elen = be16_to_cpu(event_buf->length);
> +
> + /* in case of a previous error mark all trailing buffers
> + * as not accepted */
> + if (sccb->h.response_code !=
> + cpu_to_be16(SCLP_RC_NORMAL_COMPLETION)) {
> + event_buf->flags &= ~(SCLP_EVENT_BUFFER_ACCEPTED);
> + } else {
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
> + QTAILQ_FOREACH(kid, &event_facility->sbus.qbus.children,
> sibling) {
> + DeviceState *qdev = kid->child;
> + event = (SCLPEvent *) qdev;
> + ec = SCLP_EVENT_GET_CLASS(event);
> +
> + if (ec->write_event_data &&
> + ec->event_type() == event_buf->type) {
> + sccb->h.response_code = cpu_to_be16(
> + ec->write_event_data(event, event_buf));
> + break;
> + }
> + }
> + }
> + event_buf = (void *) event_buf + elen;
> + }
> +}
> +
> +static int write_event_data(SCCB *sccb)
> +{
> + if (sccb->h.function_code != SCLP_FC_NORMAL_WRITE) {
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
> + goto out;
> + }
> + if (be16_to_cpu(sccb->h.length) < 8) {
> + sccb->h.response_code =
> cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
> + goto out;
> + }
> + /* first check the sum of all events */
> + if (check_sccb_events(sccb)) {
> + goto out;
> + }
> + /* then execute */
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> + handle_sccb_write_events(sccb);
> +
> +out:
> + return 0;
> +}
> +
> +static void handle_sccb_read_events(SCCB *sccb, unsigned int mask)
> +{
> + int slen;
> + unsigned elen = 0;
> + BusChild *kid;
> + SCLPEvent *event;
> + SCLPEventClass *ec;
> + EventBufferHeader *event_buf;
> + ReadEventData *red = (ReadEventData *) sccb;
> +
> + SCLPEventFacility *event_facility = sclp_bus->event_facility->instance;
> +
> + event_buf = &red->ebh;
> + event_buf->length = 0;
> + slen = sizeof(sccb->data);
> + QTAILQ_FOREACH(kid, &event_facility->sbus.qbus.children, sibling) {
> + DeviceState *qdev = kid->child;
> + event = (SCLPEvent *) qdev;
> + ec = SCLP_EVENT_GET_CLASS(event);
> +
> + if (mask & ec->get_send_mask()) {
> + if (ec->read_event_data(event, event_buf, &slen)) {
> + sccb->h.response_code =
> cpu_to_be16(SCLP_RC_NORMAL_COMPLETION);
> + }
> + }
> + elen = be16_to_cpu(event_buf->length);
> + event_buf = (void *) event_buf + elen;
> + }
> +
> + 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);
> + }
> +}
> +
> +static int read_event_data(SCCB *sccb)
> +{
> + unsigned int sclp_active_selection_mask;
> + unsigned int sclp_cp_receive_mask;
> +
> + ReadEventData *red = (ReadEventData *) sccb;
> +
> + if (be16_to_cpu(sccb->h.length) != SCCB_SIZE) {
> + sccb->h.response_code =
> cpu_to_be16(SCLP_RC_INSUFFICIENT_SCCB_LENGTH);
> + goto out;
> + }
> +
> + sclp_cp_receive_mask = get_guest_receive_mask();
> +
> + /* get active selection mask */
> + 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(red->mask))) {
> + sccb->h.response_code =
> + cpu_to_be16(SCLP_RC_INVALID_SELECTION_MASK);
> + goto out;
> + }
> + sclp_active_selection_mask = be32_to_cpu(red->mask);
> + break;
> + default:
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_FUNCTION);
> + goto out;
> + }
> +
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_NO_EVENT_BUFFERS_STORED);
> + handle_sccb_read_events(sccb, sclp_active_selection_mask);
> +
> +out:
> + return 0;
> +}
> +
> +static int write_event_mask(SCCB *sccb)
> +{
> + WriteEventMask *we_mask = (WriteEventMask *) 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(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 */
> + set_guest_receive_mask(be32_to_cpu(we_mask->cp_receive_mask));
> +
> + /* return the SCLP's capability masks to the guest */
> + we_mask->send_mask = cpu_to_be32(get_host_send_mask());
> + we_mask->receive_mask = cpu_to_be32(get_host_receive_mask());
> +
> + sccb->h.response_code = cpu_to_be32(SCLP_RC_NORMAL_COMPLETION);
> +
> +out:
> + return 0;
> +}
> +
> +/* qemu object creation and initialization functions */
> +
> +#define TYPE_SCLP_EVENTS_BUS "s390-sclp-events-bus"
> +#define SCLP_EVENTS_BUS(obj) OBJECT_CHECK(SCLPS390Bus, (obj),\
> + TYPE_SCLP_EVENTS_BUS)
> +
> +static void sclp_events_bus_class_init(ObjectClass *klass, void *data)
> +{
> +}
> +
> +static const TypeInfo s390_sclp_events_bus_info = {
> + .name = TYPE_SCLP_EVENTS_BUS,
> + .parent = TYPE_BUS,
> + .instance_size = sizeof(SCLPS390Bus),
> + .class_init = sclp_events_bus_class_init,
> +};
> +
> +static int command_handler(SCCB *sccb, uint64_t code)
> +{
> + int r = 0;
> +
> + switch (code) {
> + case SCLP_CMD_READ_EVENT_DATA:
> + r = read_event_data(sccb);
> + break;
> + case SCLP_CMD_WRITE_EVENT_DATA:
> + r = write_event_data(sccb);
> + break;
> + case SCLP_CMD_WRITE_EVENT_MASK:
> + r = write_event_mask(sccb);
> + break;
> + default:
> +#ifdef DEBUG_HELPER
> + printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
> +#endif
> + sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
> + break;
> + }
> + return r;
> +}
> +
> +static int init_event_facility(S390SCLPDevice *sdev)
> +{
> + SCLPEventFacility *event_facility;
> +
> + event_facility = g_malloc0(sizeof(SCLPEventFacility));
> + sdev->instance = event_facility;
> + sdev->sclp_command_handler = command_handler;
> + sdev->event_pending = event_pending;
> +
> + /* Spawn a new sclp-events facility */
> + qbus_create_inplace(&event_facility->sbus.qbus,
> + TYPE_SCLP_EVENTS_BUS, (DeviceState *)sdev, NULL);
> + event_facility->sbus.qbus.allow_hotplug = 0;
> + event_facility->sbus.event_facility = event_facility;
> + event_facility->qdev = (DeviceState *) sdev;
> +
> +
> + return 0;
> +}
> +
> +static void init_event_facility_class(ObjectClass *klass, void *data)
> +{
> + S390SCLPDeviceClass *k = SCLP_S390_DEVICE_CLASS(klass);
> +
> + k->init = init_event_facility;
> +}
> +
> +static TypeInfo s390_sclp_event_facility_info = {
> + .name = "s390-sclp-event-facility",
> + .parent = TYPE_DEVICE_S390_SCLP,
> + .instance_size = sizeof(S390SCLPDevice),
> + .class_init = init_event_facility_class,
> +};
> +
> +static int event_qdev_init(DeviceState *qdev)
> +{
> + SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
> + SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
> +
> + return child->init(event);
> +}
> +
> +static int event_qdev_exit(DeviceState *qdev)
> +{
> + SCLPEvent *event = DO_UPCAST(SCLPEvent, qdev, qdev);
> + SCLPEventClass *child = SCLP_EVENT_GET_CLASS(event);
> + if (child->exit) {
> + child->exit(event);
> + }
> + return 0;
> +}
> +
> +static void event_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->bus_type = TYPE_SCLP_EVENTS_BUS;
> + dc->unplug = qdev_simple_unplug_cb;
> + dc->init = event_qdev_init;
> + dc->exit = event_qdev_exit;
> +}
> +
> +static TypeInfo s390_sclp_event_type_info = {
> + .name = TYPE_SCLP_EVENT,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(SCLPEvent),
> + .class_init = event_class_init,
> + .class_size = sizeof(SCLPEventClass),
> + .abstract = true,
> +};
> +
> +static void register_types(void)
> +{
> + type_register_static(&s390_sclp_events_bus_info);
> + type_register_static(&s390_sclp_event_facility_info);
> + type_register_static(&s390_sclp_event_type_info);
> +}
> +type_init(register_types)
> diff --git a/hw/s390-event-facility.h b/hw/s390-event-facility.h
> new file mode 100644
> index 0000000..938fb4b
> --- /dev/null
> +++ b/hw/s390-event-facility.h
> @@ -0,0 +1,107 @@
> +/*
> + * SCLP
> + * Event Facility definitions
> + *
> + * Copyright IBM, Corp. 2007, 2012
> + *
> + * Authors:
> + * Heinz Graalfs <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
> + * the COPYING file in the top-level directory.
> + *
> + */
> +
> +#ifndef _QEMU_S390_SCLP_EVENT_FACILITY_H
> +#define _QEMU_S390_SCLP_EVENT_FACILITY_H
> +
> +#include "qdev.h"
> +#include "qemu-thread.h"
> +
> +/* SCLP event types */
> +#define SCLP_EVENT_ASCII_CONSOLE_DATA 0x1a
> +#define SCLP_EVENT_SIGNAL_QUIESCE 0x1d
> +
> +/* SCLP event masks */
> +#define SCLP_EVENT_MASK_SIGNAL_QUIESCE 0x00000008
> +#define SCLP_EVENT_MASK_MSG_ASCII 0x00000040
> +
> +#define SCLP_UNCONDITIONAL_READ 0x00
> +#define SCLP_SELECTIVE_READ 0x01
> +
> +#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 WriteEventMask {
> + SCCBHeader h;
> + 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)) WriteEventMask;
QEMU_PACKED, also below.
> +
> +typedef struct EventBufferHeader {
> + uint16_t length;
> + uint8_t type;
> + uint8_t flags;
> + uint16_t _reserved;
> +} __attribute__((packed)) EventBufferHeader;
> +
> +typedef struct WriteEventData {
> + SCCBHeader h;
> + EventBufferHeader ebh;
> +} __attribute__((packed)) WriteEventData;
> +
> +typedef struct ReadEventData {
> + SCCBHeader h;
> + EventBufferHeader ebh;
> + uint32_t mask;
> +} __attribute__((packed)) ReadEventData;
> +
> +typedef struct SCLPEvent {
> + DeviceState qdev;
> + QemuMutex lock;
> + bool event_pending;
> + uint32_t event_type;
> + char *name;
> +} SCLPEvent;
> +
> +typedef struct SCLPEventClass {
> + DeviceClass parent_class;
> + int (*init)(SCLPEvent *event);
> + int (*exit)(SCLPEvent *event);
> +
> + /* get SCLP's send mask */
> + unsigned int (*get_send_mask)(void);
> +
> + /* get SCLP's receive mask */
> + unsigned int (*get_receive_mask)(void);
> +
> + int (*read_event_data)(SCLPEvent *event, EventBufferHeader *evt_buf_hdr,
> + int *slen);
> +
> + int (*write_event_data)(SCLPEvent *event, EventBufferHeader
> *evt_buf_hdr);
> +
> + /* returns the supported event type */
> + int (*event_type)(void);
> +
> +} SCLPEventClass;
> +
> +static inline void lock(SCLPEvent *event)
> +{
> + qemu_mutex_lock(&event->lock);
> +}
> +
> +static inline void unlock(SCLPEvent *event)
> +{
> + qemu_mutex_unlock(&event->lock);
> +}
> +
> +#endif
> diff --git a/hw/s390-sclp.c b/hw/s390-sclp.c
> index 74a3e66..4ee04b1 100644
> --- a/hw/s390-sclp.c
> +++ b/hw/s390-sclp.c
> @@ -44,10 +44,7 @@ static int sclp_execute(SCCB *sccb, uint64_t code)
> r = read_SCP_info(sccb);
> break;
> default:
> -#ifdef DEBUG_HELPER
> - printf("KVM: invalid sclp call 0x%x / 0x%" PRIx64 "x\n", sccb, code);
> -#endif
> - sccb->h.response_code = cpu_to_be16(SCLP_RC_INVALID_SCLP_COMMAND);
> + r = sclp_bus->event_facility->sclp_command_handler(sccb, code);
> break;
> }
> return r;
> @@ -88,10 +85,12 @@ out:
>
> void sclp_service_interrupt(uint32_t sccb)
> {
> - if (!sccb) {
> + int event_pending = sclp_bus->event_facility->event_pending();
> +
> + if (!event_pending && !sccb) {
> return;
> }
> - s390_sclp_extint(sccb & ~3);
> + s390_sclp_extint((sccb & ~3) + event_pending);
> }
>
> /* qemu object creation and initialization functions */
> @@ -115,6 +114,9 @@ SCLPS390Bus *s390_sclp_bus_init(void)
> bus_state = qbus_create(TYPE_S390_SCLP_BUS, dev, "s390-sclp-bus");
> bus_state->allow_hotplug = 0;
>
> + dev = qdev_create(bus_state, "s390-sclp-event-facility");
> + qdev_init_nofail(dev);
> +
> bus = DO_UPCAST(SCLPS390Bus, bus, bus_state);
> return bus;
> }
> @@ -140,9 +142,44 @@ static TypeInfo s390_sclp_bridge_info = {
> .class_init = s390_sclp_bridge_class_init,
> };
>
> +static int s390_sclp_busdev_init(DeviceState *dev)
> +{
> + int r;
> + S390SCLPDevice *sdev = (S390SCLPDevice *)dev;
> + S390SCLPDeviceClass *sclp = SCLP_S390_DEVICE_GET_CLASS(dev);
> + SCLPS390Bus *bus = DO_UPCAST(SCLPS390Bus, bus, sdev->qdev.parent_bus);
> +
> + r = sclp->init(sdev);
> + if (!r) {
> + assert(sdev->event_pending);
> + assert(sdev->sclp_command_handler);
> + }
> + bus->event_facility = sdev;
> +
> + return r;
> +}
> +
> +static void s390_sclp_device_class_init(ObjectClass *klass, void *data)
> +{
> + DeviceClass *dc = DEVICE_CLASS(klass);
> +
> + dc->init = s390_sclp_busdev_init;
> + dc->bus_type = TYPE_S390_SCLP_BUS;
> +}
> +
> +static TypeInfo s390_sclp_device_info = {
> + .name = TYPE_DEVICE_S390_SCLP,
> + .parent = TYPE_DEVICE,
> + .instance_size = sizeof(S390SCLPDevice),
> + .class_init = s390_sclp_device_class_init,
> + .class_size = sizeof(S390SCLPDeviceClass),
> + .abstract = true,
> +};
> +
> static void s390_sclp_register_types(void)
> {
> type_register_static(&s390_sclp_bridge_info);
> type_register_static(&s390_sclp_bus_info);
> + type_register_static(&s390_sclp_device_info);
> }
> type_init(s390_sclp_register_types)
> diff --git a/hw/s390-sclp.h b/hw/s390-sclp.h
> index f7bf140..24014eb 100644
> --- a/hw/s390-sclp.h
> +++ b/hw/s390-sclp.h
> @@ -19,15 +19,35 @@
> /* SCLP command codes */
> #define SCLP_CMDW_READ_SCP_INFO 0x00020001
> #define SCLP_CMDW_READ_SCP_INFO_FORCED 0x00120001
> +#define SCLP_CMD_READ_EVENT_DATA 0x00770005
> +#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005
> +#define SCLP_CMD_READ_EVENT_DATA 0x00770005
> +#define SCLP_CMD_WRITE_EVENT_DATA 0x00760005
> +#define SCLP_CMD_WRITE_EVENT_MASK 0x00780005
>
> /* SCLP response codes */
> #define SCLP_RC_NORMAL_READ_COMPLETION 0x0010
> +#define SCLP_RC_NORMAL_COMPLETION 0x0020
> #define SCLP_RC_INVALID_SCLP_COMMAND 0x01f0
> +#define SCLP_RC_CONTAINED_EQUIPMENT_CHECK 0x0340
> +#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
> +
>
> /* Service Call Control Block (SCCB) and its elements */
>
> #define SCCB_SIZE 4096
>
> +#define SCLP_VARIABLE_LENGTH_RESPONSE 0x80
> +#define SCLP_EVENT_BUFFER_ACCEPTED 0x80
> +
> +#define SCLP_FC_NORMAL_WRITE 0
> +
> /*
> * Normally packed structures are not the right thing to do, since all code
> * must take care of endianess. We cant use ldl_phys and friends for two
> @@ -63,14 +83,37 @@ typedef struct SCCB {
>
> #define TYPE_S390_SCLP_BUS "s390-sclp-bus"
>
> +#define TYPE_DEVICE_S390_SCLP "s390-sclp-device"
> +#define SCLP_S390_DEVIVE(obj) \
> + OBJECT_CHECK(S390SCLPDevice, (obj), TYPE_DEVICE_S390_SCLP)
> +#define SCLP_S390_DEVICE_CLASS(klass) \
> + OBJECT_CLASS_CHECK(S390SCLPDeviceClass, (klass), \
> + TYPE_DEVICE_S390_SCLP)
> +#define SCLP_S390_DEVICE_GET_CLASS(obj) \
> + OBJECT_GET_CLASS(S390SCLPDeviceClass, (obj), \
> + TYPE_DEVICE_S390_SCLP)
> +
> +typedef struct SCLPEventFacility SCLPEventFacility;
> +
> typedef struct S390SCLPDevice {
> DeviceState qdev;
> + SCLPEventFacility *instance;
> + int (*sclp_command_handler)(SCCB *sccb, uint64_t code);
> + bool (*event_pending)(void);
> } S390SCLPDevice;
>
> typedef struct SCLPS390Bus {
> BusState bus;
> + S390SCLPDevice *event_facility;
> } SCLPS390Bus;
>
> +typedef struct S390SCLPDeviceClass {
> + DeviceClass qdev;
> +
> + int (*init)(S390SCLPDevice *sdev);
> +
> +} S390SCLPDeviceClass;
> +
> extern SCLPS390Bus *sclp_bus;
>
> SCLPS390Bus *s390_sclp_bus_init(void);
> diff --git a/hw/s390x/Makefile.objs b/hw/s390x/Makefile.objs
> index b2d577b..5ebde3b 100644
> --- a/hw/s390x/Makefile.objs
> +++ b/hw/s390x/Makefile.objs
> @@ -1,4 +1,4 @@
> obj-y = s390-virtio-bus.o s390-virtio.o
> -obj-y += s390-sclp.o
> +obj-y += s390-sclp.o s390-event-facility.o
>
> obj-y := $(addprefix ../,$(obj-y))
> --
> 1.7.10.5
>
>
- [Qemu-devel] [PATCH 0/6v2] s390: several sclp patches, Christian Borntraeger, 2012/07/13
- [Qemu-devel] [PATCH 1/6] s390: Fix error handling and condition code of service call, Christian Borntraeger, 2012/07/13
- [Qemu-devel] [PATCH 6/6] s390: make sclp ascii console the default, Christian Borntraeger, 2012/07/13
- [Qemu-devel] [PATCH 5/6] s390: sclp ascii console support, Christian Borntraeger, 2012/07/13
- [Qemu-devel] [PATCH 3/6] s390: sclp event support, Christian Borntraeger, 2012/07/13
- Re: [Qemu-devel] [PATCH 3/6] s390: sclp event support,
Blue Swirl <=
- [Qemu-devel] [PATCH 4/6] s390: sclp signal quiesce support, Christian Borntraeger, 2012/07/13
- [Qemu-devel] [PATCH 2/6] s390: sclp base support, Christian Borntraeger, 2012/07/13
- Re: [Qemu-devel] [PATCH 2/6] s390: sclp base support, Andreas Färber, 2012/07/20