qemu-s390x
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [qemu-s390x] [Qemu-devel] [RFC PATCH v2 1/3] s390x/ccs: add ccw-test


From: Thomas Huth
Subject: Re: [qemu-s390x] [Qemu-devel] [RFC PATCH v2 1/3] s390x/ccs: add ccw-testdev emulated device
Date: Thu, 7 Dec 2017 07:33:19 +0100
User-agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.5.0

 Hi Halil,

just a high-level review since I'm not a CSS expert...

On 08.11.2017 17:54, Halil Pasic wrote:
[...]
> I'm not really happy with the side effects of moving it to hw/misc, which
> ain't s390x specific.

Sorry, I'm missing the context - why can't this go into hw/s390x/ ?

> I've pretty much bounced off the build system, so
> I would really appreciate some help here. Currently you have to say you
> want it when you do make or it won't get compiled into your qemu. IMHO
> this device only makes sense for testing and should not be rutinely
> shipped in production builds. That is why I did not touch
> default-configs/s390x-softmmu.mak.

You could at least add a CONFIG_CCW_TESTDEV=n there, but I think the
normal QEMU policy is to enable everything by default to avoid that code
is bit-rotting, so I think "=y" is also OK there (distros can then still
disable it in downstream if they want).

> I think, I have the most problematic places marked with a  TODO
> comment in the code.
> 
> Happy reviewing and looking forward to your comments.
> ---
>  hw/misc/Makefile.objs |   1 +
>  hw/misc/ccw-testdev.c | 284 
> ++++++++++++++++++++++++++++++++++++++++++++++++++
>  hw/misc/ccw-testdev.h |  18 ++++
>  3 files changed, 303 insertions(+)
>  create mode 100644 hw/misc/ccw-testdev.c
>  create mode 100644 hw/misc/ccw-testdev.h
> 
> diff --git a/hw/misc/Makefile.objs b/hw/misc/Makefile.objs
> index 19202d90cf..b41314d096 100644
> --- a/hw/misc/Makefile.objs
> +++ b/hw/misc/Makefile.objs
> @@ -61,3 +61,4 @@ obj-$(CONFIG_AUX) += auxbus.o
>  obj-$(CONFIG_ASPEED_SOC) += aspeed_scu.o aspeed_sdmc.o
>  obj-y += mmio_interface.o
>  obj-$(CONFIG_MSF2) += msf2-sysreg.o
> +obj-$(CONFIG_CCW_TESTDEV) += ccw-testdev.o
> diff --git a/hw/misc/ccw-testdev.c b/hw/misc/ccw-testdev.c
> new file mode 100644
> index 0000000000..39cf46e90d
> --- /dev/null
> +++ b/hw/misc/ccw-testdev.c
> @@ -0,0 +1,284 @@

Please add a short description of the device in a comment here.

And don't you also want to add some license statement and/or author
information here?

> +#include "qemu/osdep.h"
> +#include "qapi/error.h"
> +#include "qemu/module.h"
> +#include "ccw-testdev.h"
> +#include "hw/s390x/css.h"
> +#include "hw/s390x/css-bridge.h"
> +#include "hw/s390x/3270-ccw.h"
> +#include "exec/address-spaces.h"
> +#include "hw/s390x/s390-virtio-hcall.h"
> +#include <error.h>
> +
> +typedef struct CcwTestDevDevice {
> +    CcwDevice parent_obj;
> +    uint16_t cu_type;
> +    uint8_t chpid_type;
> +    uint32_t op_mode;
> +    bool op_mode_locked;
> +    struct {
> +        uint32_t ring[4];
> +        unsigned int next;
> +    } fib;
> +} CcwTestDevDevice;
> +
> +typedef struct CcwTestDevClass {
> +    CCWDeviceClass parent_class;
> +    DeviceRealize parent_realize;
> +} CcwTestDevClass;
> +
> +#define TYPE_CCW_TESTDEV "ccw-testdev"
> +
> +#define CCW_TESTDEV(obj) \
> +     OBJECT_CHECK(CcwTestDevDevice, (obj), TYPE_CCW_TESTDEV)
> +#define CCW_TESTDEV_CLASS(klass) \
> +     OBJECT_CLASS_CHECK(CcwTestDevClass, (klass), TYPE_CCW_TESTDEV)
> +#define CCW_TESTDEV_GET_CLASS(obj) \
> +     OBJECT_GET_CLASS(CcwTestDevClass, (obj), TYPE_CCW_TESTDEV)
> +
> +typedef int (*ccw_cb_t)(SubchDev *, CCW1);
> +static ccw_cb_t get_ccw_cb(CcwTestDevOpMode op_mode);
> +
> +/* TODO This is the in-band set mode. We may want to get rid of it. */
> +static int set_mode_ccw(SubchDev *sch)
> +{
> +    CcwTestDevDevice *d = sch->driver_data;
> +    const char pattern[] = CCW_TST_SET_MODE_INCANTATION;
> +    char buf[sizeof(pattern)];
> +    int ret;
> +    uint32_t tmp;
> +
> +    if (d->op_mode_locked) {
> +        return -EINVAL;
> +    }
> +
> +    ret = ccw_dstream_read(&sch->cds, buf);
> +    if (ret) {
> +        return ret;
> +    }
> +    ret = strncmp(buf, pattern, sizeof(pattern));
> +    if (ret) {
> +        return 0; /* ignore malformed request -- maybe fuzzing */
> +    }
> +    ret = ccw_dstream_read(&sch->cds, tmp);
> +    if (ret) {
> +        return ret;
> +    }
> +    be32_to_cpus(&tmp);
> +    if (tmp >= OP_MODE_MAX) {
> +        return -EINVAL;
> +    }
> +    d->op_mode = tmp;
> +    sch->ccw_cb = get_ccw_cb(d->op_mode);
> +    return ret;
> +}
> +
> +

Please remove one empty line above.

> +static unsigned int abs_to_ring(unsigned int i)

IMHO a short comment above that function would be nice. If I just read
"abs_to_ring(unsigned int i)" I have a hard time to figure out what this
means.

> +{
> +    return i & 0x3;
> +}
> +
> +static int  ccw_testdev_write_fib(SubchDev *sch)
> +{
> +    CcwTestDevDevice *d = sch->driver_data;
> +    bool is_fib = true;
> +    uint32_t tmp;
> +    int ret = 0;
> +
> +    d->fib.next = 0;
> +    while (ccw_dstream_avail(&sch->cds) > 0) {
> +        ret = ccw_dstream_read(&sch->cds, tmp);
> +        if (ret) {
> +            error(0, -ret, "fib");

Where does this error() function come from? I failed to spot its location...

> +            break;
> +        }
> +        d->fib.ring[abs_to_ring(d->fib.next)] = cpu_to_be32(tmp);
> +        if (d->fib.next > 2) {
> +            tmp = (d->fib.ring[abs_to_ring(d->fib.next - 1)]
> +                  + d->fib.ring[abs_to_ring(d->fib.next - 2)]);
> +            is_fib = tmp ==  d->fib.ring[abs_to_ring(d->fib.next)];
> +            if (!is_fib) {
> +                break;
> +            }
> +        }
> +        ++(d->fib.next);

I'd prefer to do this without braces, e.g.:

           d->fib.next++;

> +    }
> +    if (!is_fib) {
> +        sch->curr_status.scsw.ctrl &= ~SCSW_ACTL_START_PEND;
> +        sch->curr_status.scsw.ctrl |= SCSW_STCTL_PRIMARY |
> +                                      SCSW_STCTL_SECONDARY |
> +                                      SCSW_STCTL_ALERT |
> +                                      SCSW_STCTL_STATUS_PEND;
> +        sch->curr_status.scsw.count = ccw_dstream_residual_count(&sch->cds);
> +        sch->curr_status.scsw.cpa = sch->channel_prog + 8;
> +        sch->curr_status.scsw.dstat =  SCSW_DSTAT_UNIT_EXCEP;
> +        return -EIO;
> +    }
> +    return ret;
> +}
> +
> +static int  ccw_testdev_read_fib(SubchDev *sch)
> +{
> +    uint32_t l = 0, m = 1, n = 0;
> +    int ret = 0;
> +
> +    while (ccw_dstream_avail(&sch->cds) > 0) {
> +        n = m + l;
> +        l = m;
> +        m = n;
> +        ret = ccw_dstream_read(&sch->cds, n);
> +    }
> +    return ret;
> +}
> +
> +static int ccw_testdev_ccw_cb_mode_fib(SubchDev *sch, CCW1 ccw)
> +{
> +    switch (ccw.cmd_code) {
> +    case CCW_CMD_READ:
> +        ccw_testdev_read_fib(sch);
> +        break;
> +    case CCW_CMD_WRITE:
> +        return ccw_testdev_write_fib(sch);
> +    case CCW_CMD_CTL_MODE:
> +        return set_mode_ccw(sch);
> +    default:
> +        return -EINVAL;
> +    }
> +    return 0;
> +}
> +
> +static int ccw_testdev_ccw_cb_mode_nop(SubchDev *sch, CCW1 ccw)
> +{
> +    CcwTestDevDevice *d = sch->driver_data;
> +
> +    if (!d->op_mode_locked && ccw.cmd_code == CCW_CMD_CTL_MODE) {
> +        return set_mode_ccw(sch);
> +    }
> +    return 0;
> +}
> +
> +static ccw_cb_t get_ccw_cb(CcwTestDevOpMode op_mode)
> +{
> +    switch (op_mode) {
> +    case OP_MODE_FIB:
> +        return ccw_testdev_ccw_cb_mode_fib;
> +    case OP_MODE_NOP:
> +    default:
> +        return ccw_testdev_ccw_cb_mode_nop;

Do we really want to use "nop" for unknown modes? Or should there rather
be a ccw_testdev_ccw_cb_mode_error instead, too?

> +    }
> +}
> +
> +static void ccw_testdev_realize(DeviceState *ds, Error **errp)
> +{
> +    uint16_t chpid;
> +    CcwTestDevDevice *dev = CCW_TESTDEV(ds);
> +    CcwTestDevClass *ctc = CCW_TESTDEV_GET_CLASS(dev);
> +    CcwDevice *cdev = CCW_DEVICE(ds);
> +    BusState *qbus = qdev_get_parent_bus(ds);
> +    VirtualCssBus *cbus = VIRTUAL_CSS_BUS(qbus);
> +    SubchDev *sch;
> +    Error *err = NULL;
> +
> +    sch = css_create_sch(cdev->devno, true, cbus->squash_mcss, errp);
> +    if (!sch) {
> +        return;
> +    }
> +
> +    sch->driver_data = dev;
> +    cdev->sch = sch;
> +    chpid = css_find_free_chpid(sch->cssid);
> +
> +    if (chpid > MAX_CHPID) {
> +        error_setg(&err, "No available chpid to use.");
> +        goto out_err;
> +    }
> +
> +    sch->id.reserved = 0xff;
> +    sch->id.cu_type = dev->cu_type;
> +    css_sch_build_virtual_schib(sch, (uint8_t)chpid,
> +                                dev->chpid_type);
> +    sch->ccw_cb = get_ccw_cb(dev->op_mode);
> +    sch->do_subchannel_work = do_subchannel_work_virtual;
> +
> +

Please remove superfluous empty line.

> +    ctc->parent_realize(ds, &err);
> +    if (err) {
> +        goto out_err;
> +    }
> +
> +    css_generate_sch_crws(sch->cssid, sch->ssid, sch->schid,
> +                          ds->hotplugged, 1);
> +    return;
> +
> +out_err:
> +    error_propagate(errp, err);
> +    css_subch_assign(sch->cssid, sch->ssid, sch->schid, sch->devno, NULL);
> +    cdev->sch = NULL;
> +    g_free(sch);
> +}
> +
> +static Property ccw_testdev_properties[] = {
> +    DEFINE_PROP_UINT16("cu_type", CcwTestDevDevice, cu_type,
> +                        0xfffe), /* only numbers used for real HW */
> +    DEFINE_PROP_UINT8("chpid_type", CcwTestDevDevice, chpid_type,
> +                       0x25), /* took FC, TODO discuss */
> +    DEFINE_PROP_UINT32("op_mode", CcwTestDevDevice, op_mode,
> +                       0), /* TODO discuss */
> +    DEFINE_PROP_BOOL("op_mode_locked", CcwTestDevDevice, op_mode_locked,
> +                       false), /* TODO discuss */
> +    DEFINE_PROP_END_OF_LIST(),
> +};
> +
> +/* TODO This is the out-of-band variant. We may want to get rid of it */

I agree, this should rather go away in the final version.

> +static int set_mode_diag(const uint64_t *args)
> +{
> +    uint64_t subch_id = args[0];
> +    uint64_t op_mode = args[1];
> +    SubchDev *sch;
> +    CcwTestDevDevice *dev;
> +    int cssid, ssid, schid, m;
> +
> +    if (ioinst_disassemble_sch_ident(subch_id, &m, &cssid, &ssid, &schid)) {
> +        return -EINVAL;
> +    }
> +    sch = css_find_subch(m, cssid, ssid, schid);
> +    if (!sch || !css_subch_visible(sch)) {
> +        return -EINVAL;
> +    }
> +    dev = CCW_TESTDEV(sch->driver_data);
> +    if (dev->op_mode_locked) {
> +        return op_mode == dev->op_mode ? 0 : -EINVAL;
> +    }
> +    dev->op_mode = op_mode;
> +    sch->ccw_cb = get_ccw_cb(dev->op_mode);
> +    return 0;
> +}
> +
> +static void ccw_testdev_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    CcwTestDevClass *ctc = CCW_TESTDEV_CLASS(klass);
> +
> +    dc->props = ccw_testdev_properties;
> +    dc->bus_type = TYPE_VIRTUAL_CSS_BUS;
> +    ctc->parent_realize = dc->realize;
> +    dc->realize = ccw_testdev_realize;
> +    dc->hotpluggable = false;
> +
> +    s390_register_virtio_hypercall(CCW_TST_DIAG_500_SUB, set_mode_diag);
> +}
> +
> +static const TypeInfo ccw_testdev_info = {
> +    .name = TYPE_CCW_TESTDEV,
> +    .parent = TYPE_CCW_DEVICE,
> +    .instance_size = sizeof(CcwTestDevDevice),
> +    .class_init = ccw_testdev_class_init,
> +    .class_size = sizeof(CcwTestDevClass),
> +};
> +
> +static void ccw_testdev_register(void)
> +{
> +    type_register_static(&ccw_testdev_info);
> +}
> +
> +type_init(ccw_testdev_register)
> diff --git a/hw/misc/ccw-testdev.h b/hw/misc/ccw-testdev.h
> new file mode 100644
> index 0000000000..f4d4570f5e
> --- /dev/null
> +++ b/hw/misc/ccw-testdev.h
> @@ -0,0 +1,18 @@

Add some license statement and/or author information here?

> +#ifndef HW_s390X_CCW_TESTDEV_H
> +#define HW_s390X_CCW_TESTDEV_H
> +
> +typedef enum CcwTestDevOpMode {
> +    OP_MODE_NOP = 0,
> +    OP_MODE_FIB = 1,
> +    OP_MODE_MAX /* extremal element */
> +} CcwTestDevOpMode;
> +
> +#define CCW_CMD_READ 0x01U
> +#define CCW_CMD_WRITE 0x02U
> +
> +#define CCW_CMD_CTL_MODE 0x07U
> +#define CCW_TST_SET_MODE_INCANTATION "SET MODE="
> +/* Subcode for diagnose 500 (virtio hypercall). */
> +#define CCW_TST_DIAG_500_SUB 254
> +
> +#endif

 Thomas



reply via email to

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