/*
 * Vhost-user vsock virtio device
 *
 * Copyright 2020 Red Hat, Inc.
 *
 * This work is licensed under the terms of the GNU GPL, version 2 or
 * (at your option) any later version.  See the COPYING file in the
 * top-level directory.
 */

#include "qemu/osdep.h"

#include "qapi/error.h"
#include "qemu/error-report.h"
#include "hw/qdev-properties.h"
#include "hw/qdev-properties-system.h"
#include "hw/virtio/vhost-user-vsock.h"

static const int user_feature_bits[] = {
    VIRTIO_F_VERSION_1,
    VIRTIO_RING_F_INDIRECT_DESC,
    VIRTIO_RING_F_EVENT_IDX,
    VIRTIO_F_NOTIFY_ON_EMPTY,
    VHOST_INVALID_FEATURE_BIT
};

static void vuv_get_config(VirtIODevice *vdev, uint8_t *config)
{
    VHostUserVSock *vsock = VHOST_USER_VSOCK(vdev);

    memcpy(config, &vsock->vsockcfg, sizeof(struct virtio_vsock_config));
}

static int vuv_handle_config_change(struct vhost_dev *dev)
{
    VHostUserVSock *vsock = VHOST_USER_VSOCK(dev->vdev);
    Error *local_err = NULL;
    int ret = vhost_dev_get_config(dev, (uint8_t *)&vsock->vsockcfg,
                                   sizeof(struct virtio_vsock_config),
                                   &local_err);
    if (ret < 0) {
        error_report_err(local_err);
        return -1;
    }

    virtio_notify_config(dev->vdev);

    return 0;
}

const VhostDevConfigOps vsock_ops = {
    .vhost_dev_config_notifier = vuv_handle_config_change,
};

static void vuv_set_status(VirtIODevice *vdev, uint8_t status)
{
    VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);
    bool should_start = status & VIRTIO_CONFIG_S_DRIVER_OK;

    if (!vdev->vm_running) {
        should_start = false;
    }

    if (vvc->vhost_dev.started == should_start) {
        return;
    }

    if (should_start) {
        int ret = vhost_vsock_common_start(vdev);
        if (ret < 0) {
            return;
        }
    } else {
        vhost_vsock_common_stop(vdev);
    }
}

static uint64_t vuv_get_features(VirtIODevice *vdev,
                                 uint64_t features,
                                 Error **errp)
{
    VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(vdev);

    features = vhost_get_features(&vvc->vhost_dev, user_feature_bits, features);

    return vhost_vsock_common_get_features(vdev, features, errp);
}

static const VMStateDescription vuv_vmstate = {
    .name = "vhost-user-vsock",
    .unmigratable = 1,
};

static void vuv_device_realize(DeviceState *dev, Error **errp)
{
    VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);
    int ret;

    if (!vsock->conf.chardev.chr) {
        error_setg(errp, "missing chardev");
        return;
    }

    if (!vhost_user_init(&vsock->vhost_user, &vsock->conf.chardev, errp)) {
        return;
    }

    vhost_vsock_common_realize(vdev);

    vhost_dev_set_config_notifier(&vvc->vhost_dev, &vsock_ops);

    ret = vhost_dev_init(&vvc->vhost_dev, &vsock->vhost_user,
                         VHOST_BACKEND_TYPE_USER, 0, errp);
    if (ret < 0) {
        goto err_virtio;
    }

    ret = vhost_dev_get_config(&vvc->vhost_dev, (uint8_t *)&vsock->vsockcfg,
                               sizeof(struct virtio_vsock_config), errp);
    if (ret < 0) {
        goto err_vhost_dev;
    }

    return;

err_vhost_dev:
    vhost_dev_cleanup(&vvc->vhost_dev);
err_virtio:
    vhost_vsock_common_unrealize(vdev);
    vhost_user_cleanup(&vsock->vhost_user);
    return;
}

static void vuv_device_unrealize(DeviceState *dev)
{
    VHostVSockCommon *vvc = VHOST_VSOCK_COMMON(dev);
    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
    VHostUserVSock *vsock = VHOST_USER_VSOCK(dev);

    /* This will stop vhost backend if appropriate. */
    vuv_set_status(vdev, 0);

    vhost_dev_cleanup(&vvc->vhost_dev);

    vhost_vsock_common_unrealize(vdev);

    vhost_user_cleanup(&vsock->vhost_user);

}

static Property vuv_properties[] = {
    DEFINE_PROP_CHR("chardev", VHostUserVSock, conf.chardev),
    DEFINE_PROP_END_OF_LIST(),
};

static void vuv_class_init(ObjectClass *klass, void *data)
{
    DeviceClass *dc = DEVICE_CLASS(klass);
    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);

    device_class_set_props(dc, vuv_properties);
    dc->vmsd = &vuv_vmstate;
    vdc->realize = vuv_device_realize;
    vdc->unrealize = vuv_device_unrealize;
    vdc->get_features = vuv_get_features;
    vdc->get_config = vuv_get_config;
    vdc->set_status = vuv_set_status;
}

static const TypeInfo vuv_info = {
    .name = TYPE_VHOST_USER_VSOCK,
    .parent = TYPE_VHOST_VSOCK_COMMON,
    .instance_size = sizeof(VHostUserVSock),
    .class_init = vuv_class_init,
};

static void vuv_register_types(void)
{
    type_register_static(&vuv_info);
}

type_init(vuv_register_types)
