qemu-devel
[Top][All Lists]
Advanced

[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
>
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]