aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--adapter.c16
-rw-r--r--vhost_loopback.c2
-rw-r--r--vhost_user_can.c322
-rw-r--r--vhost_user_can.h57
-rw-r--r--vhost_user_loopback.c11
-rw-r--r--virtio_loopback.c20
-rw-r--r--virtio_loopback.h4
8 files changed, 410 insertions, 24 deletions
diff --git a/Makefile b/Makefile
index 2aa7c13..45d6725 100644
--- a/Makefile
+++ b/Makefile
@@ -33,7 +33,7 @@ endif
INCL += -I .
DEPS = adapter.h vhost_user_loopback.h event_notifier.h virtio_loopback.h
-SRC_C = event_notifier.c vhost_user_loopback.c virtio_loopback.c virtio_rng.c virtio_input.c vhost_user_input.c vhost_user_blk.c vhost_user_rng.c vhost_user_sound.c vhost_user_gpio.c vhost_loopback.c adapter.c
+SRC_C = event_notifier.c vhost_user_loopback.c virtio_loopback.c virtio_rng.c virtio_input.c vhost_user_input.c vhost_user_blk.c vhost_user_rng.c vhost_user_sound.c vhost_user_gpio.c vhost_user_can.c vhost_loopback.c adapter.c
OBJS = $(SRC_C:.c=.o)
BINS = adapter
diff --git a/adapter.c b/adapter.c
index 75b5681..68effcd 100644
--- a/adapter.c
+++ b/adapter.c
@@ -49,6 +49,7 @@
#include "vhost_user_input.h"
#include "vhost_user_gpio.h"
#include "vhost_user_sound.h"
+#include "vhost_user_can.h"
#ifdef DEBUG
@@ -158,9 +159,10 @@ int find_arg(int argc, char **argv, char *str)
int val_device_arg(char *str)
{
char *adapter_devices[] = {"vrng", "vhurng", "vhublk", "vhuinput",
- "vhusnd", "vhugpio"};
- char *vhu_devices[] = {"vhurng", "vhublk", "vhuinput", "vhusnd", "vhugpio"};
- int adapter_devices_num = 6, i;
+ "vhusnd", "vhugpio", "vhucan"};
+ char *vhu_devices[] = {"vhurng", "vhublk", "vhuinput", "vhusnd",
+ "vhugpio", "vhucan"};
+ int adapter_devices_num = 7, i;
for (i = 0; i < adapter_devices_num; i++) {
if (!strcmp(adapter_devices[i], str)) {
@@ -173,8 +175,9 @@ int val_device_arg(char *str)
bool check_vhu_device(char *str)
{
- char *vhu_devices[] = {"vhurng", "vhublk", "vhuinput", "vhusnd", "vhugpio"};
- int vhu_devices_num = 5, i;
+ char *vhu_devices[] = {"vhurng", "vhublk", "vhuinput", "vhusnd",
+ "vhugpio", "vhucan"};
+ int vhu_devices_num = 6, i;
for (i = 0; i < vhu_devices_num; i++) {
if (!strcmp(vhu_devices[i], str)) {
@@ -297,6 +300,9 @@ int main(int argc, char **argv)
case 6:
vu_gpio_device_realize();
break;
+ case 7:
+ vhost_user_can_realize();
+ break;
default:
exit(1);
}
diff --git a/vhost_loopback.c b/vhost_loopback.c
index af725e3..1855ee8 100644
--- a/vhost_loopback.c
+++ b/vhost_loopback.c
@@ -330,7 +330,7 @@ void update_mem_table(VirtIODevice *vdev)
static int vhost_dev_set_vring_enable(struct vhost_dev *hdev, int enable)
{
- DBG("vhost_dev_set_vring_enable not yet implemented\n");
+ DBG("vhost_dev_set_vring_enable:\n");
/*
* For vhost-user devices, if VHOST_USER_F_PROTOCOL_FEATURES has not
diff --git a/vhost_user_can.c b/vhost_user_can.c
new file mode 100644
index 0000000..8a1b1ae
--- /dev/null
+++ b/vhost_user_can.c
@@ -0,0 +1,322 @@
+/*
+ * Virtio CAN Device
+ *
+ * Based on virtio_can.h of OpenSynergy's virtio-can RFC
+ * https://github.com/OpenSynergy/qemu/tree/virtio-can-spec-rfc-v3
+ *
+ * Copyright (C) 2021-2023 OpenSynergy GmbH
+ * Copyright (c) 2023 Virtual Open Systems SAS.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/param.h>
+
+/* Project header files */
+#include "vhost_user_can.h"
+
+#ifdef DEBUG
+#define DBG(...) printf("vhost-user-can: " __VA_ARGS__)
+#else
+#define DBG(...)
+#endif /* DEBUG */
+
+/***************************** vhost-user-can ******************************/
+
+static const int user_feature_bits[] = {
+ VIRTIO_F_VERSION_1,
+ VIRTIO_RING_F_INDIRECT_DESC,
+ VIRTIO_RING_F_EVENT_IDX,
+ VIRTIO_F_RING_RESET,
+ VIRTIO_F_NOTIFY_ON_EMPTY,
+ VHOST_INVALID_FEATURE_BIT
+};
+
+static void vhost_user_can_get_config(VirtIODevice *vdev, uint8_t *config)
+{
+ VHostUserCan *can = vdev->vhucan;
+
+ DBG("vhost_user_can_get_config: Not yet implemented!\n");
+
+ /*
+ * TODO : Add this check depend on 'busoff' value
+ * if (vcan->busoff) {
+ * config->status = cpu_to_le32(VIRTIO_CAN_S_CTRL_BUSOFF);
+ * } else {
+ * config->status = cpu_to_le32(0);
+ * }
+ */
+
+ memcpy(config, &can->config, sizeof(struct virtio_can_config));
+}
+
+
+static void vhost_user_can_start(VirtIODevice *vdev)
+{
+ VHostUserCan *vhucan = vdev->vhucan;
+ VirtioBus *k = vdev->vbus;
+ int ret;
+ int i;
+
+ DBG("vhost_user_can_start(...)\n");
+
+ if (!k->set_guest_notifiers) {
+ DBG("binding does not support guest notifiers\n");
+ return;
+ }
+
+ ret = vhost_dev_enable_notifiers(vhucan->vhost_dev, vdev);
+ if (ret < 0) {
+ DBG("Error enabling host notifiers: %d\n", -ret);
+ return;
+ }
+
+ ret = k->set_guest_notifiers(k->vdev, vhucan->vhost_dev->nvqs, true);
+ if (ret < 0) {
+ DBG("Error binding guest notifier: %d\n", -ret);
+ goto err_host_notifiers;
+ }
+
+ vhucan->vhost_dev->acked_features = vdev->guest_features;
+
+ ret = vhost_dev_start(vhucan->vhost_dev, vdev, true);
+ if (ret < 0) {
+ DBG("Error starting vhost: %d\n", -ret);
+ goto err_guest_notifiers;
+ }
+
+ /*
+ * guest_notifier_mask/pending not used yet, so just unmask
+ * everything here. virtio-pci will do the right thing by
+ * enabling/disabling irqfd.
+ */
+ for (i = 0; i < vhucan->vhost_dev->nvqs; i++) {
+ vhost_virtqueue_mask(vhucan->vhost_dev, vdev, i, false);
+ }
+
+ /* Wait a bit for the vrings to be set in vhost-user-device */
+ sleep(1);
+
+ return;
+
+err_guest_notifiers:
+err_host_notifiers:
+ DBG("vhu_start error\n");
+ return;
+}
+
+static void vhost_user_can_stop(VirtIODevice *vdev)
+{
+ DBG("vhost_user_can_stop: not yet implemented\n");
+}
+
+static void vhost_user_can_set_status(VirtIODevice *vdev, uint8_t status)
+{
+ VHostUserCan *vhucan = vdev->vhucan;
+ bool should_start = virtio_device_started(vdev, status);
+ DBG("vhost_user_can_set_status: %d\n", status);
+
+ if (vhucan->vhost_dev->started == should_start) {
+ DBG("can->vhost_dev->started == should_start\n");
+ return;
+ }
+
+ if (should_start) {
+ vhost_user_can_start(vdev);
+ } else {
+ vhost_user_can_stop(vdev);
+ }
+}
+
+static uint64_t vhost_user_can_get_features(VirtIODevice *vdev,
+ uint64_t features)
+{
+ VHostUserCan *s = vdev->vhucan;
+
+ DBG("vhost_user_can_get_features()\n");
+
+ return vhost_get_features(s->vhost_dev, user_feature_bits, features);
+}
+
+static void vhost_user_can_can_handle_output(VirtIODevice *vdev, VirtQueue *vq)
+{
+ /*
+ * Not normally called; it's the daemon that handles the queue;
+ * however virtio's cleanup path can call this.
+ */
+ DBG("vhost_user_can_can_handle_output: Not yet implemented!\n");
+}
+
+/*
+ * TODO: Add it later
+ * static void vhost_sound_guest_notifier_mask(VirtIODevice *vdev, int idx,
+ * bool mask)
+ */
+
+/*
+ * TODO: Add it later
+ * static bool vhost_sound_guest_notifier_pending(VirtIODevice *vdev,
+ * int idx)
+ */
+
+static int vhost_user_can_can_config_change(struct vhost_dev *dev)
+{
+ VHostUserCan *vhucan = dev->vdev->vhucan;
+ DBG("vhost_user_can_can_config_change: Not yet implemented!\n");
+
+ int ret = vhost_dev_get_config(dev, (uint8_t *)&vhucan->config,
+ sizeof(struct virtio_can_config));
+ if (ret < 0) {
+ DBG("vhost_user_can_sound_config_change error\n");
+ return -1;
+ }
+
+ virtio_notify_config(dev->vdev);
+
+ return 0;
+}
+
+const VhostDevConfigOps can_config_ops = {
+ .vhost_dev_config_notifier = vhost_user_can_can_config_change,
+};
+
+static void vhost_user_can_init(VirtIODevice *vdev);
+
+void vhost_user_can_realize()
+{
+ VirtIODevice *vdev = global_vdev;
+ int ret;
+
+ DBG("vhost_user_can_device_realize\n");
+
+ /* This needs to be added */
+ proxy = (VirtIOMMIOProxy *)malloc(sizeof(VirtIOMMIOProxy));
+ *proxy = (VirtIOMMIOProxy) {
+ .legacy = 1,
+ };
+
+ /* VIRTIO_ID_CAN is 36, check virtio_ids.h in linux*/
+ virtio_dev_init(vdev, "virtio-can", 36, sizeof(vdev->vhucan->config));
+ vhost_user_can_init(global_vdev);
+
+ /* add queues */
+ vdev->vhucan->ctrl_vq = virtio_add_queue(vdev, 64,
+ vhost_user_can_can_handle_output);
+ vdev->vhucan->tx_vq = virtio_add_queue(vdev, 64,
+ vhost_user_can_can_handle_output);
+ vdev->vhucan->rx_vq = virtio_add_queue(vdev, 64,
+ vhost_user_can_can_handle_output);
+ vdev->vhucan->vhost_dev->nvqs = 3;
+ vdev->vhucan->num_queues = 3;
+ vdev->vhucan->queue_size = 64;
+
+ /* NOTE: global_vdev->vqs == vhucan->virtqs */
+ vdev->vqs = (VirtQueue **)malloc(sizeof(VirtQueue *)
+ * global_vdev->vhucan->num_queues);
+ vdev->vqs[0] = vdev->vhucan->tx_vq;
+ vdev->vqs[1] = vdev->vhucan->rx_vq;
+ vdev->vqs[2] = vdev->vhucan->ctrl_vq;
+
+ vdev->vhucan->vhost_vqs = (struct vhost_virtqueue *)malloc(
+ sizeof(struct vhost_virtqueue) *
+ vdev->vhucan->num_queues);
+
+ /* Set up vhost device */
+ vdev->vhucan->vhost_dev->num_queues = vdev->vhucan->num_queues;
+ vdev->vhucan->vhost_dev->nvqs = vdev->vhucan->num_queues;
+ vdev->vhucan->vhost_dev->vqs = vdev->vhucan->vhost_vqs;
+ vdev->vhucan->vhost_dev->vq_index = 0;
+ vdev->vhucan->vhost_dev->backend_features = 0;
+
+ vhost_dev_set_config_notifier(vdev->vhucan->vhost_dev, &can_config_ops);
+
+ /* TODO: Add error handling */
+ vhost_dev_init(vdev->vhucan->vhost_dev);
+
+ /* Pass the new obtained features */
+ global_vdev->host_features = vdev->vhucan->vhost_dev->features;
+
+ ret = vhost_dev_get_config(vdev->vhucan->vhost_dev,
+ (uint8_t *)&vdev->vhucan->config,
+ sizeof(struct virtio_can_config));
+ if (ret < 0) {
+ goto vhost_dev_init_failed;
+ }
+
+ vdev->vdev_class->print_config((uint8_t *)&vdev->vhucan->config);
+
+ return;
+
+vhost_dev_init_failed:
+ DBG("vhost_dev_init_failed\n");
+ return;
+}
+
+static void vhost_user_can_device_unrealize(VirtIODevice *vdev)
+{
+ DBG("vhost_user_blk_device_unrealize not yet implemented\n");
+}
+
+static struct vhost_dev *vhost_user_can_get_vhost(VirtIODevice *vdev)
+{
+ VHostUserCan *vhucan = vdev->vhucan;
+ return vhucan->vhost_dev;
+}
+
+static void print_config_can(uint8_t *config_data)
+{
+ struct virtio_can_config *config_strct =
+ (struct virtio_can_config *)config_data;
+
+ DBG("print_config_can:\n");
+
+ /* # of available physical jacks */
+ DBG("\tuint16_t status: %u\n", config_strct->status);
+}
+
+static void virtio_dev_class_init(VirtIODevice *vdev)
+{
+ DBG("virtio_dev_class_init\n");
+
+ vdev->vdev_class = (VirtioDeviceClass *)malloc(sizeof(VirtioDeviceClass));
+ vdev->vdev_class->parent = vdev;
+ vdev->vdev_class->realize = vhost_user_can_realize;
+ vdev->vdev_class->unrealize = vhost_user_can_device_unrealize;
+ vdev->vdev_class->get_config = vhost_user_can_get_config;
+ vdev->vdev_class->get_features = vhost_user_can_get_features;
+ vdev->vdev_class->set_status = vhost_user_can_set_status;
+ vdev->vdev_class->update_mem_table = update_mem_table;
+ vdev->vdev_class->print_config = print_config_can;
+}
+
+static void vhost_user_can_init(VirtIODevice *vdev)
+{
+ DBG("vhost_user_can_init\n");
+
+ VHostUserCan *vhucan = (VHostUserCan *)malloc(sizeof(VHostUserCan));
+ vdev->vhucan = vhucan;
+ vdev->nvqs = &vdev->vhdev->nvqs;
+ vhucan->parent = vdev;
+ vhucan->virtqs = vdev->vqs;
+ vhucan->vhost_dev = vdev->vhdev;
+
+ virtio_dev_class_init(vdev);
+ virtio_loopback_bus_init(vdev->vbus);
+}
diff --git a/vhost_user_can.h b/vhost_user_can.h
new file mode 100644
index 0000000..6e2e5d5
--- /dev/null
+++ b/vhost_user_can.h
@@ -0,0 +1,57 @@
+/*
+ * Virtio CAN Device
+ *
+ * Based on virtio_can.h of OpenSynergy's virtio-can RFC
+ * https://github.com/OpenSynergy/qemu/tree/virtio-can-spec-rfc-v3
+ *
+ * Copyright (C) 2021-2023 OpenSynergy GmbH
+ * Copyright (c) 2023 Virtual Open Systems SAS.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2.
+ *
+ * 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.
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef VHOST_USER_CAN
+#define VHOST_USER_CAN
+
+#include "virtio_loopback.h"
+#include "vhost_loopback.h"
+#include "vhost_user_loopback.h"
+
+/* The following are defined into virtio_can.h -- Delete them in the future */
+#define VIRTIO_CAN_S_CTRL_BUSOFF (1u << 0) /* Controller BusOff */
+struct virtio_can_config {
+ /* CAN controller status */
+ __le16 status;
+};
+
+typedef struct VHostUserCan {
+ VirtIODevice *parent;
+ struct vhost_virtqueue *vhost_vqs;
+ VirtQueue **virtqs;
+ uint16_t num_queues;
+ uint32_t queue_size;
+ struct virtio_can_config config;
+ struct vhost_dev *vhost_dev;
+ VirtQueue *ctrl_vq;
+ VirtQueue *tx_vq;
+ VirtQueue *rx_vq;
+ /* Support classic CAN */
+ bool support_can_classic;
+ /* Support CAN FD */
+ bool support_can_fd;
+} VHostUserCan;
+
+void vhost_user_can_realize(void);
+
+#endif /* VHOST_USER_CAN */
diff --git a/vhost_user_loopback.c b/vhost_user_loopback.c
index 85b9405..31830ae 100644
--- a/vhost_user_loopback.c
+++ b/vhost_user_loopback.c
@@ -847,7 +847,8 @@ static int vhost_user_fill_set_mem_table_msg(struct vhost_user *u,
u->region_rb_offset[i] = offset;
u->region_rb[i] = mr->ram_block;
} else if (*fd_num == VHOST_MEMORY_BASELINE_NREGIONS) {
- DBG("Failed preparing vhost-user memory table msg: %d\n", *fd_num);
+ DBG("Failed preparing vhost-user memory table msg: %lu\n",
+ *fd_num);
return -1;
}
vhost_user_fill_msg_region(&region_buffer, reg, offset);
@@ -1180,7 +1181,7 @@ int vhost_user_set_mem_table(struct vhost_dev *dev)
}
/* Update message parameters */
- DBG("\nfd_num: %d\n", fd_num);
+ DBG("\nfd_num: %lu\n", fd_num);
msg.fd_num = fd_num;
memcpy(msg.fds, fds, fd_num * sizeof(int));
@@ -1585,14 +1586,14 @@ void vhost_dev_init(struct vhost_dev *vhdev)
*/
vhdev->features = features;
- DBG("vhdev->backend_features 0x%llx\n", vhdev->backend_features);
- DBG("vhdev->features 0x%llx\n", vhdev->features);
+ DBG("vhdev->backend_features 0x%lx\n", vhdev->backend_features);
+ DBG("vhdev->features 0x%lx\n", vhdev->features);
}
int vhost_user_set_vring_enable(struct vhost_dev *dev, int enable)
{
int i;
- DBG("vhost_user_set_vring_enable not yet implemented\n");
+ DBG("vhost_user_set_vring_enable:\n");
if (!virtio_has_feature(dev->features, VHOST_USER_F_PROTOCOL_FEATURES)) {
DBG("Does not have VHOST_USER_F_PROTOCOL_FEATURES\n");
diff --git a/virtio_loopback.c b/virtio_loopback.c
index e95c648..8b57589 100644
--- a/virtio_loopback.c
+++ b/virtio_loopback.c
@@ -1032,20 +1032,19 @@ void *loopback_event_select(void *_e)
}
if (retval > 0) {
+ if (pthread_mutex_lock(&interrupt_lock) != 0) {
+ printf("[ERROR] Locking failed\n");
+ exit(1);
+ }
DBG("\n\nEvent has come from the vhost-user-device "
"(eventfd: %d) -> event_count: %d (select value: %d)\n\n",
rfd, eventfd_count, retval);
if (event_notifier_test_and_clear(e)) {
- if (pthread_mutex_lock(&interrupt_lock) == 0) {
- eventfd_count++;
- virtio_irq(vq);
- pthread_mutex_unlock(&interrupt_lock);
- } else {
- printf("[ERROR] Locking failed\n");
- exit(1);
- }
+ eventfd_count++;
+ virtio_irq(vq);
}
+ pthread_mutex_unlock(&interrupt_lock);
}
}
}
@@ -1460,7 +1459,6 @@ static uint64_t virtio_loopback_read(VirtIODevice *vdev, uint64_t offset,
case VIRTIO_MMIO_MAGIC_VALUE:
return VIRT_MAGIC;
case VIRTIO_MMIO_VERSION:
- DBG("VIRTIO_MMIO_VERSION ->\n");
if (proxy->legacy) {
DBG("VIRTIO_MMIO_VERSION -> legacy\n");
return VIRT_VERSION_LEGACY;
@@ -1602,8 +1600,6 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset,
case VIRTIO_MMIO_DRIVER_FEATURES:
if (proxy->legacy) {
if (proxy->guest_features_sel) {
- DBG("attempt to write guest features with "
- "guest_features_sel > 0 in legacy mode\n");
DBG("Set driver features: 0x%lx\n", value << 32);
virtio_set_features(vdev, value << 32);
} else {
@@ -1691,7 +1687,7 @@ void virtio_loopback_write(VirtIODevice *vdev, uint64_t offset,
/* TODO: To be implemented */
break;
case VIRTIO_MMIO_QUEUE_NOTIFY:
- DBG("VIRTIO_MMIO_QUEUE_NOTIFY: vq_index -> %d, notify_cnt: %d\n",
+ DBG("VIRTIO_MMIO_QUEUE_NOTIFY: vq_index -> %lu, notify_cnt: %d\n",
value, notify_cnt++);
if (value < VIRTIO_QUEUE_MAX) {
virtio_queue_notify(vdev, value);
diff --git a/virtio_loopback.h b/virtio_loopback.h
index 34bae2f..cd59a5a 100644
--- a/virtio_loopback.h
+++ b/virtio_loopback.h
@@ -364,6 +364,7 @@ typedef struct VHostUserBlk VHostUserBlk;
typedef struct VhostUserInput VhostUserInput;
typedef struct VHostUserGPIO VHostUserGPIO;
typedef struct VHostUserSound VHostUserSound;
+typedef struct VHostUserCan VHostUserCan;
typedef struct VirtioBus VirtioBus;
typedef struct VirtIODevice {
@@ -405,6 +406,7 @@ typedef struct VirtIODevice {
VhostUserInput *vhuinput;
VHostUserSound *vhusnd;
VHostUserGPIO *vhugpio;
+ VHostUserCan *vhucan;
} VirtIODevice;
typedef struct efd_data {
@@ -659,7 +661,9 @@ uint32_t get_vqs_max_size(VirtIODevice *vdev);
* Legacy name for VIRTIO_F_ACCESS_PLATFORM
* (for compatibility with old userspace)
*/
+#ifndef VIRTIO_F_IOMMU_PLATFORM
#define VIRTIO_F_IOMMU_PLATFORM 33
+#endif
/* QEMU Aligned functions */
/*