From patchwork Fri Jun 17 15:55:01 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christian Pinto X-Patchwork-Id: 9184523 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id EE5AE608A6 for ; Fri, 17 Jun 2016 16:21:47 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id D7D1B27DD0 for ; Fri, 17 Jun 2016 16:21:47 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id CC6E92833F; Fri, 17 Jun 2016 16:21:47 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id BDA4B27DD0 for ; Fri, 17 Jun 2016 16:21:46 +0000 (UTC) Received: from localhost ([::1]:58806 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bDwWf-0007mu-S1 for patchwork-qemu-devel@patchwork.kernel.org; Fri, 17 Jun 2016 12:21:45 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:53220) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bDw7L-0006dz-IV for qemu-devel@nongnu.org; Fri, 17 Jun 2016 11:55:41 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bDw7J-00019E-06 for qemu-devel@nongnu.org; Fri, 17 Jun 2016 11:55:35 -0400 Received: from mail-wm0-x241.google.com ([2a00:1450:400c:c09::241]:33658) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bDw7I-00018t-Kd for qemu-devel@nongnu.org; Fri, 17 Jun 2016 11:55:32 -0400 Received: by mail-wm0-x241.google.com with SMTP id r201so755576wme.0 for ; Fri, 17 Jun 2016 08:55:32 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=virtualopensystems-com.20150623.gappssmtp.com; s=20150623; h=from:to:cc:subject:date:message-id:in-reply-to:references; bh=3AoXRYOt6xcvR1iUzPd5bt4RUbaTtJgBtppJ6waiqNg=; b=a2Zdy1XGXs/2sCKPjKKc6SCoA2b/Is1BGaeldOedSUiKLw4pgmAZ5XS/lPZOu3vA2F NcWpFDajC2A99+pIfH6TbS+C7FuBvRL4VBh2G/vRXm9/ETYkhcqxHUnrnc0SLjOmOYTu evywDMYbdbUFttx+Ta60iVvL4x3MjbPi4hhaKtERa7S4iPdBj3b8qcTWyNDwpM/iTN+y DbyKTTaTl7a3/jJLOKfighosKXutkS+0O8e4StxdfG8hzrPRrq0f9TYmrWN1Iph7KBOU MqmsG8o+hLGZXScgYCzSYDmkTr3KuHl7fe/jg02pO/5jT2J4eV+42Tf8evvehni1jiJ8 c4bg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references; bh=3AoXRYOt6xcvR1iUzPd5bt4RUbaTtJgBtppJ6waiqNg=; b=hFGgWkxY7weUktST90wI3x2Gd6gYTNcm0MTmu9jjWjvAU4okg6M5aFuBDCMQgnbc8p r11DeUDALPD7h0S4mz6f3u5zL5UNViDfV/tQfnvc/plRhlCIVrXb2WdTvsV4Q9r9Ly6b 38DHIYH5MuPXT3LPuxay3TaH74e1Pb+jPV4Dbd2YMpkEH+swEqukhY5IkOwgttjztOdq eo8JE7O/hvXRbMFonlNTVQaYYJiAGD2RYBwPxr/4IUAGwBWFC6U9twu+xgEfUu8977v6 26teCgNRAF0JPx/JqmnAROb4S7zdLoABpnMuBodKYgqen/5ZbmBLyHSa5IPllBNSyjKO jSQg== X-Gm-Message-State: ALyK8tJgmxWYMEQLEuR3gw/SwaSsV7tElTax+SKzGDiWZhWhJJ7zsz2JztPbavJKkoai9g== X-Received: by 10.195.11.40 with SMTP id ef8mr2977391wjd.137.1466178931705; Fri, 17 Jun 2016 08:55:31 -0700 (PDT) Received: from bumma.localdomain ([151.67.13.17]) by smtp.googlemail.com with ESMTPSA id q189sm254937wmd.19.2016.06.17.08.55.30 (version=TLS1_2 cipher=ECDHE-RSA-AES128-SHA bits=128/128); Fri, 17 Jun 2016 08:55:31 -0700 (PDT) From: Christian Pinto To: qemu-devel@nongnu.org Date: Fri, 17 Jun 2016 17:55:01 +0200 Message-Id: <1466178903-2184-5-git-send-email-c.pinto@virtualopensystems.com> X-Mailer: git-send-email 1.9.1 In-Reply-To: <1466178903-2184-1-git-send-email-c.pinto@virtualopensystems.com> References: <1466178903-2184-1-git-send-email-c.pinto@virtualopensystems.com> X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2a00:1450:400c:c09::241 Subject: [Qemu-devel] [RFC v3 4/6] hw/misc: sdm virtio device X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Claudio.Fontana@huawei.com, Jani.Kokkonen@huawei.com, tech@virtualopensystems.com, b.reynal@virtualopensystems.com, Christian Pinto Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP From: Baptiste Reynal This is the virtio implementation for an SDM device. Parameters are: comm=[sdm_communication_id] specifies the communication channel master=[true/false] - configure the SDM device as master or slave num_slaves=[slave_number] - if master is true, specifies the number of slaves len-signals=[signals_number] - specifies the number of signals signals[x]=[signal_id] - add a signal to the device, with the ID x Signed-off-by: Christian Pinto Signed-off-by: Baptiste Reynal --- v2 -> v3 - add configuration space to virtio sdm device - add accessor methods (get, set) to sdm virtio device model - max num_slave changes propagated to communication channel to realloc slaves array - align virtio device ID to device specification RFC submitted to virtio-dev --- --- hw/virtio/Makefile.objs | 1 + hw/virtio/virtio-sdm.c | 303 +++++++++++++++++++++++++++++++++++++++ include/hw/virtio/virtio-sdm.h | 58 ++++++++ linux-headers/linux/virtio_sdm.h | 58 ++++++++ 4 files changed, 420 insertions(+) create mode 100644 hw/virtio/virtio-sdm.c create mode 100644 include/hw/virtio/virtio-sdm.h create mode 100644 linux-headers/linux/virtio_sdm.h diff --git a/hw/virtio/Makefile.objs b/hw/virtio/Makefile.objs index 19b224a..7e44bc4 100644 --- a/hw/virtio/Makefile.objs +++ b/hw/virtio/Makefile.objs @@ -2,6 +2,7 @@ common-obj-y += virtio-rng.o common-obj-$(CONFIG_VIRTIO_PCI) += virtio-pci.o common-obj-y += virtio-bus.o common-obj-y += virtio-mmio.o +obj-$(CONFIG_SDM) += virtio-sdm.o obj-$(CONFIG_VIRTIO) += dataplane/ obj-y += virtio.o virtio-balloon.o diff --git a/hw/virtio/virtio-sdm.c b/hw/virtio/virtio-sdm.c new file mode 100644 index 0000000..a210ced --- /dev/null +++ b/hw/virtio/virtio-sdm.c @@ -0,0 +1,303 @@ +/* + * Copyright (C) 2016 - Virtual Open Systems + * Authors: Christian Pinto + * Baptiste Reynal + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#include + +#include "qemu/iov.h" +#include "qemu/error-report.h" +#include "hw/virtio/virtio.h" +#include "hw/virtio/virtio-sdm.h" + +typedef void (*cmd_handler)(VirtIOSdm *sdm, union sdm_cmd_params); +/** + * Command handler for signal type commands. + * Invoked when the command is received from the guest + */ +static void handler_signal(VirtIOSdm *sdm, union sdm_cmd_params params) +{ + SDMSignalData signal; + DEBUG_PRINT("handler_signal: SIGNAL %d, SLAVE_ID %d\n", params.sig.type, + params.sig.slave_id); + + signal.type = params.sig.type; + signal.slave = params.sig.slave_id; + memcpy(&signal.payload, ¶ms.sig.payload, 2 * sizeof(uint32_t)); + + sdm_communication_signal(sdm->sdmc, SDM_DEVICE(sdm), &signal); +} + +static cmd_handler sdm_cmd_handlers[] = { + [SDM_SIGNAL_CMD] = handler_signal, +}; + +/** + * Send a command to the guest virtio-driver + */ +static void send_cmd_to_guest(VirtIOSdm *sdm, + struct sdm_cmd cmd) +{ + VirtQueueElement elem; + VirtIODevice * vdev = VIRTIO_DEVICE(sdm); + + if (!virtqueue_pop(sdm->hg_vq, &elem)) { + return; + } + + if (iov_from_buf(elem.in_sg, elem.in_num, 0, &cmd, sizeof(cmd))) { + virtqueue_push(sdm->hg_vq, &elem, sizeof(cmd)); + virtio_notify(vdev, sdm->hg_vq); + DEBUG_PRINT("Sending command %d of type %d\n", + cmd.cmd, cmd.params.sig.type); + } else { + error_report("virtio-sdm - Failed to issue command id 0x%x\n", + cmd.cmd); + } +} + +/** + * guest -> host virtqueue handler. + * Calls the handler assoociated to the command received over the virtqueue + */ +static void handle_guest_host_queue(VirtIODevice *vdev, VirtQueue *vq) +{ + VirtQueueElement elem; + struct sdm_cmd cmd; + + if (!virtqueue_pop(vq,&elem)) + return; + + if (!iov_to_buf(elem.out_sg, elem.out_num, 0, &cmd, sizeof(cmd))) + return; + + DEBUG_PRINT("Command received 0x%x\n", cmd.cmd); + + if (cmd.cmd >= ARRAY_SIZE(sdm_cmd_handlers) || + !sdm_cmd_handlers[cmd.params.sig.type]) { + error_report("virtio-sdm - unrecognized command %x\n", cmd.cmd); + return; + } + + sdm_cmd_handlers[cmd.params.sig.type](VIRTIO_SDM(vdev), cmd.params); +} + +/** + * Guest sends commands over this virtqueue only to add an empty + * buffer to be later used by the host. + */ +static void handle_host_guest_queue(VirtIODevice *vdev, VirtQueue *vq) { + VirtIOSdm *sdm = VIRTIO_SDM(vdev); + + sdm->busy = false; +} + +static uint64_t get_features(VirtIODevice *vdev, uint64_t requested_features, + Error **errp) +{ + return requested_features; +} + +static void virtio_sdm_get_config(VirtIODevice *vdev, uint8_t *config_data) +{ + VirtIOSdm *sdm = VIRTIO_SDM(vdev); + struct virtio_sdm_config config; + + config.master = sdm->master ? 1 : 0; + config.max_slaves = cpu_to_le16(sdm->num_slaves); + config.registered_slaves = cpu_to_le16(sdm->last_slave); + + memcpy(config_data, &config, sizeof(struct virtio_sdm_config)); +} + +static void virtio_sdm_set_config(VirtIODevice *vdev, + const uint8_t *config_data) +{ + VirtIOSdm *sdm = VIRTIO_SDM(vdev); + struct virtio_sdm_config config; + uint16_t max_slaves; + + memcpy(&config, config_data, sizeof(struct virtio_sdm_config)); + max_slaves = le16_to_cpu(config.max_slaves); + if(max_slaves > sdm->num_slaves) { + sdm_communication_update_num_slaves(sdm->sdmc, SDM_DEVICE(sdm), + max_slaves); + } else { + printf("WARNING - virtio-sdm: reducing the maximum number of slaves" + "is not allowed. The new value should be bigger than the" + "current one.\n"); + } +} + +static void virtio_sdm_device_realize(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + VirtIOSdm *sdm = VIRTIO_SDM(dev); + int i; + + virtio_init(vdev, "virtio-sdm", VIRTIO_ID_SDM, + sizeof(struct virtio_sdm_config)); + + sdm->hg_vq = virtio_add_queue(vdev, 128, handle_host_guest_queue); + sdm->gh_vq = virtio_add_queue(vdev, 128, handle_guest_host_queue); + + sdm->signals = calloc(sdm->num_signals, sizeof(SDMSignal)); + for (i=0; inum_signals; i++) { + sdm->signals[i] = (SDMSignal *) object_resolve_path_type( + sdm->signals_name[i], + TYPE_SDM_SIGNAL, false); + if (!sdm->signals[i]) { + error_report("virtio-sdm: Cannot find signal %s", + sdm->signals_name[i]);; + } + } + + sdm_communication_connect(sdm->sdmc, SDM_DEVICE(sdm)); +} + +static void virtio_sdm_device_unrealize(DeviceState *dev, Error **errp) +{ + VirtIODevice *vdev = VIRTIO_DEVICE(dev); + virtio_cleanup(vdev); +} + +static int virtio_sdm_accept(SDMDevice *sdm) +{ + VirtIOSdm *sdmv = VIRTIO_SDM(sdm); + + if (sdmv->last_slave >= sdmv->num_slaves) + return -1; + + return ++sdmv->last_slave; +} + +static int virtio_sdm_notify(SDMDevice *sdm, SDMSignalData *signal) +{ + VirtIOSdm *sdmv = VIRTIO_SDM(sdm); + SDMSignal *hw_signal ; + struct sdm_cmd cmd; + + if (signal->type > sdmv->num_signals) { + return 0; + } + + hw_signal = sdmv->signals[signal->type]; + + if (!hw_signal) { + return 0; + } + + sdm_signal_hw_ops(hw_signal, signal); + + if (!sdm_signal_hw_only(hw_signal)) { + if (sdmv->busy) { + return -1; + } + + sdmv->busy = true; + + cmd.cmd = SDM_SIGNAL_CMD; + cmd.params.sig.type = signal->type; + cmd.params.sig.slave_id = signal->slave; + memcpy(cmd.params.sig.payload, signal->payload, 2 * sizeof(uint32_t)); + + DEBUG_PRINT("Forward %d %d\n", cmd.params.sig.type, cmd.params.sig.slave_id); + send_cmd_to_guest(sdmv, cmd); + } + + return 0; +} + +static int virtio_sdm_get_num_slaves(SDMDevice *sdm) +{ + VirtIOSdm *sdmv = VIRTIO_SDM(sdm); + + return sdmv->num_slaves; +} + +static int virtio_sdm_set_num_slaves(SDMDevice *sdm, uint16_t num_slaves) +{ + VirtIOSdm *sdmv = VIRTIO_SDM(sdm); + + sdmv->num_slaves = num_slaves; + + return 0; +} + +static bool virtio_sdm_is_master(SDMDevice *sdm) +{ + VirtIOSdm *sdmv = VIRTIO_SDM(sdm); + + return sdmv->master; +} + +static Property sdm_virtio_properties[] = { + DEFINE_PROP_UINT32("num-slaves", VirtIOSdm, num_slaves, 1), + DEFINE_PROP_BOOL("master", VirtIOSdm, master, false), + DEFINE_PROP_ARRAY("signals", VirtIOSdm, num_signals, signals_name, + qdev_prop_string, char *), + DEFINE_PROP_END_OF_LIST(), +}; + +static void virtio_sdm_class_init(ObjectClass *klass, void *data) +{ + DeviceClass *dc = DEVICE_CLASS(klass); + VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass); + SDMDeviceClass *sdmc = SDM_DEVICE_CLASS(klass); + + set_bit(DEVICE_CATEGORY_MISC, dc->categories); + vdc->realize = virtio_sdm_device_realize; + vdc->unrealize = virtio_sdm_device_unrealize; + vdc->get_features = get_features; + vdc->get_config = virtio_sdm_get_config; + vdc->set_config = virtio_sdm_set_config; + + sdmc->accept = virtio_sdm_accept; + sdmc->notify = virtio_sdm_notify; + sdmc->get_num_slaves = virtio_sdm_get_num_slaves; + sdmc->set_num_slaves = virtio_sdm_set_num_slaves; + sdmc->is_master = virtio_sdm_is_master; + + dc->props = sdm_virtio_properties; +} + +static void virtio_sdm_init(Object *obj) +{ + VirtIOSdm *sdm = VIRTIO_SDM(obj); + + object_property_add_link(obj, "comm", TYPE_SDM_COMMUNICATION, + (Object **)&sdm->sdmc, + qdev_prop_allow_set_link_before_realize, + OBJ_PROP_LINK_UNREF_ON_RELEASE, &error_abort); + + sdm->busy = false; +} + +static const TypeInfo virtio_sdm_info = { + .name = TYPE_VIRTIO_SDM, + .parent = TYPE_VIRTIO_DEVICE, + .instance_size = sizeof(VirtIOSdm), + .class_init = virtio_sdm_class_init, + .instance_init = virtio_sdm_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_SDM_DEVICE }, + { } + } +}; + +static void virtio_register_types(void) +{ + type_register_static(&virtio_sdm_info); +} + +type_init(virtio_register_types) diff --git a/include/hw/virtio/virtio-sdm.h b/include/hw/virtio/virtio-sdm.h new file mode 100644 index 0000000..c86d112 --- /dev/null +++ b/include/hw/virtio/virtio-sdm.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 - Virtual Open Systems + * Author: Christian Pinto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _QEMU_VIRTIO_SDM_H +#define _QEMU_VIRTIO_SDM_H + +#include "hw/virtio/virtio.h" +#include "hw/misc/sdm-device.h" +#include "hw/misc/sdm-communication.h" + +/*#define DEBUG_SDM*/ +#ifdef DEBUG_SDM +#define DEBUG_PRINT(fmt, ...) \ + do {printf("virtio-sdm - " fmt, ## __VA_ARGS__); } while (0) +#else +#define DEBUG_PRINT(fmt, ...) +#endif + +#define TYPE_VIRTIO_SDM "virtio-sdm-device" +#define VIRTIO_SDM(obj) \ + OBJECT_CHECK(VirtIOSdm, (obj), TYPE_VIRTIO_SDM) +#define VIRTIO_SDM_GET_PARENT_CLASS(obj) \ + OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_SDM) + +/* The Virtio ID for the virtio SDM device */ +#define VIRTIO_ID_SDM 19 + +typedef struct VirtIOSdm { + VirtIODevice parent_obj; + + SDMCommunication *sdmc; + + bool master; + bool busy; + + uint32_t num_slaves; + uint32_t last_slave; + + uint32_t num_signals; + char **signals_name; + SDMSignal **signals; + + VirtQueue *hg_vq; + VirtQueue *gh_vq; +} VirtIOSdm; + +#endif /*_QEMU_VIRTIO_SDM_H*/ diff --git a/linux-headers/linux/virtio_sdm.h b/linux-headers/linux/virtio_sdm.h new file mode 100644 index 0000000..c43a932 --- /dev/null +++ b/linux-headers/linux/virtio_sdm.h @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 - Virtual Open Systems + * Author: Christian Pinto + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License, version 2, as + * published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef _LINUX_VIRTIO_SDM_H +#define _LINUX_VIRTIO_SDM_H +#include +#include +#include +/* the commands the host can issue to a virtio-sdm guest */ +enum sdm_cmd_type { + SDM_SIGNAL_CMD, +}; + +enum sdm_signal_type { + SDM_IRQ, + SDM_BOOT, +}; + +union sdm_cmd_params { + /** + * This command is used to communicate signals between + * guest and host. + * The slave_id to which signal triggering/reception is + * associated, the type and signal and 2 32-bits registers + * for payload are transmitted. + */ + struct { + __u16 type; + __u16 slave_id; + + __u32 payload[2]; + } sig; + __u32 padding[4]; +}; + +struct sdm_cmd { + enum sdm_cmd_type cmd; + union sdm_cmd_params params; +}; + +struct virtio_sdm_config { + __u8 master; + __u16 max_slaves; + __u16 registered_slaves; +}; + +#endif /* _LINUX_VIRTIO_SDM_H */