|
@@ -17,6 +17,7 @@
|
|
#include "qapi/qapi-commands-qom.h"
|
|
#include "qapi/qapi-commands-qom.h"
|
|
#include "qapi/qmp/qobject.h"
|
|
#include "qapi/qmp/qobject.h"
|
|
#include "qapi/qmp/qjson.h"
|
|
#include "qapi/qmp/qjson.h"
|
|
|
|
+#include "hw/virtio/vhost-user.h"
|
|
|
|
|
|
#include "standard-headers/linux/virtio_ids.h"
|
|
#include "standard-headers/linux/virtio_ids.h"
|
|
#include "standard-headers/linux/vhost_types.h"
|
|
#include "standard-headers/linux/vhost_types.h"
|
|
@@ -30,32 +31,13 @@
|
|
#include "standard-headers/linux/virtio_iommu.h"
|
|
#include "standard-headers/linux/virtio_iommu.h"
|
|
#include "standard-headers/linux/virtio_mem.h"
|
|
#include "standard-headers/linux/virtio_mem.h"
|
|
#include "standard-headers/linux/virtio_vsock.h"
|
|
#include "standard-headers/linux/virtio_vsock.h"
|
|
|
|
+#include "standard-headers/linux/virtio_gpio.h"
|
|
|
|
|
|
#include CONFIG_DEVICES
|
|
#include CONFIG_DEVICES
|
|
|
|
|
|
#define FEATURE_ENTRY(name, desc) (qmp_virtio_feature_map_t) \
|
|
#define FEATURE_ENTRY(name, desc) (qmp_virtio_feature_map_t) \
|
|
{ .virtio_bit = name, .feature_desc = desc }
|
|
{ .virtio_bit = name, .feature_desc = desc }
|
|
|
|
|
|
-enum VhostUserProtocolFeature {
|
|
|
|
- VHOST_USER_PROTOCOL_F_MQ = 0,
|
|
|
|
- VHOST_USER_PROTOCOL_F_LOG_SHMFD = 1,
|
|
|
|
- VHOST_USER_PROTOCOL_F_RARP = 2,
|
|
|
|
- VHOST_USER_PROTOCOL_F_REPLY_ACK = 3,
|
|
|
|
- VHOST_USER_PROTOCOL_F_NET_MTU = 4,
|
|
|
|
- VHOST_USER_PROTOCOL_F_BACKEND_REQ = 5,
|
|
|
|
- VHOST_USER_PROTOCOL_F_CROSS_ENDIAN = 6,
|
|
|
|
- VHOST_USER_PROTOCOL_F_CRYPTO_SESSION = 7,
|
|
|
|
- VHOST_USER_PROTOCOL_F_PAGEFAULT = 8,
|
|
|
|
- VHOST_USER_PROTOCOL_F_CONFIG = 9,
|
|
|
|
- VHOST_USER_PROTOCOL_F_BACKEND_SEND_FD = 10,
|
|
|
|
- VHOST_USER_PROTOCOL_F_HOST_NOTIFIER = 11,
|
|
|
|
- VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD = 12,
|
|
|
|
- VHOST_USER_PROTOCOL_F_RESET_DEVICE = 13,
|
|
|
|
- VHOST_USER_PROTOCOL_F_INBAND_NOTIFICATIONS = 14,
|
|
|
|
- VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS = 15,
|
|
|
|
- VHOST_USER_PROTOCOL_F_MAX
|
|
|
|
-};
|
|
|
|
-
|
|
|
|
/* Virtio transport features mapping */
|
|
/* Virtio transport features mapping */
|
|
static const qmp_virtio_feature_map_t virtio_transport_map[] = {
|
|
static const qmp_virtio_feature_map_t virtio_transport_map[] = {
|
|
/* Virtio device transport features */
|
|
/* Virtio device transport features */
|
|
@@ -136,6 +118,9 @@ static const qmp_virtio_feature_map_t vhost_user_protocol_map[] = {
|
|
FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS, \
|
|
FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS, \
|
|
"VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS: Configuration for "
|
|
"VHOST_USER_PROTOCOL_F_CONFIGURE_MEM_SLOTS: Configuration for "
|
|
"memory slots supported"),
|
|
"memory slots supported"),
|
|
|
|
+ FEATURE_ENTRY(VHOST_USER_PROTOCOL_F_STATUS, \
|
|
|
|
+ "VHOST_USER_PROTOCOL_F_STATUS: Querying and notifying back-end "
|
|
|
|
+ "device status supported"),
|
|
{ -1, "" }
|
|
{ -1, "" }
|
|
};
|
|
};
|
|
|
|
|
|
@@ -178,6 +163,8 @@ static const qmp_virtio_feature_map_t virtio_blk_feature_map[] = {
|
|
"VIRTIO_BLK_F_DISCARD: Discard command supported"),
|
|
"VIRTIO_BLK_F_DISCARD: Discard command supported"),
|
|
FEATURE_ENTRY(VIRTIO_BLK_F_WRITE_ZEROES, \
|
|
FEATURE_ENTRY(VIRTIO_BLK_F_WRITE_ZEROES, \
|
|
"VIRTIO_BLK_F_WRITE_ZEROES: Write zeroes command supported"),
|
|
"VIRTIO_BLK_F_WRITE_ZEROES: Write zeroes command supported"),
|
|
|
|
+ FEATURE_ENTRY(VIRTIO_BLK_F_SECURE_ERASE, \
|
|
|
|
+ "VIRTIO_BLK_F_SECURE_ERASE: Secure erase supported"),
|
|
FEATURE_ENTRY(VIRTIO_BLK_F_ZONED, \
|
|
FEATURE_ENTRY(VIRTIO_BLK_F_ZONED, \
|
|
"VIRTIO_BLK_F_ZONED: Zoned block devices"),
|
|
"VIRTIO_BLK_F_ZONED: Zoned block devices"),
|
|
#ifndef VIRTIO_BLK_NO_LEGACY
|
|
#ifndef VIRTIO_BLK_NO_LEGACY
|
|
@@ -301,6 +288,14 @@ static const qmp_virtio_feature_map_t virtio_net_feature_map[] = {
|
|
FEATURE_ENTRY(VIRTIO_NET_F_CTRL_MAC_ADDR, \
|
|
FEATURE_ENTRY(VIRTIO_NET_F_CTRL_MAC_ADDR, \
|
|
"VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control "
|
|
"VIRTIO_NET_F_CTRL_MAC_ADDR: MAC address set through control "
|
|
"channel"),
|
|
"channel"),
|
|
|
|
+ FEATURE_ENTRY(VIRTIO_NET_F_NOTF_COAL, \
|
|
|
|
+ "VIRTIO_NET_F_NOTF_COAL: Device supports coalescing notifications"),
|
|
|
|
+ FEATURE_ENTRY(VIRTIO_NET_F_GUEST_USO4, \
|
|
|
|
+ "VIRTIO_NET_F_GUEST_USO4: Driver can receive USOv4"),
|
|
|
|
+ FEATURE_ENTRY(VIRTIO_NET_F_GUEST_USO6, \
|
|
|
|
+ "VIRTIO_NET_F_GUEST_USO4: Driver can receive USOv6"),
|
|
|
|
+ FEATURE_ENTRY(VIRTIO_NET_F_HOST_USO, \
|
|
|
|
+ "VIRTIO_NET_F_HOST_USO: Device can receive USO"),
|
|
FEATURE_ENTRY(VIRTIO_NET_F_HASH_REPORT, \
|
|
FEATURE_ENTRY(VIRTIO_NET_F_HASH_REPORT, \
|
|
"VIRTIO_NET_F_HASH_REPORT: Hash reporting supported"),
|
|
"VIRTIO_NET_F_HASH_REPORT: Hash reporting supported"),
|
|
FEATURE_ENTRY(VIRTIO_NET_F_RSS, \
|
|
FEATURE_ENTRY(VIRTIO_NET_F_RSS, \
|
|
@@ -471,6 +466,18 @@ static const qmp_virtio_feature_map_t virtio_rng_feature_map[] = {
|
|
};
|
|
};
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+/* virtio/vhost-gpio features mapping */
|
|
|
|
+#ifdef CONFIG_VHOST_USER_GPIO
|
|
|
|
+static const qmp_virtio_feature_map_t virtio_gpio_feature_map[] = {
|
|
|
|
+ FEATURE_ENTRY(VIRTIO_GPIO_F_IRQ, \
|
|
|
|
+ "VIRTIO_GPIO_F_IRQ: Device supports interrupts on GPIO lines"),
|
|
|
|
+ FEATURE_ENTRY(VHOST_USER_F_PROTOCOL_FEATURES, \
|
|
|
|
+ "VHOST_USER_F_PROTOCOL_FEATURES: Vhost-user protocol features "
|
|
|
|
+ "negotiation supported"),
|
|
|
|
+ { -1, "" }
|
|
|
|
+};
|
|
|
|
+#endif
|
|
|
|
+
|
|
#define CONVERT_FEATURES(type, map, is_status, bitmap) \
|
|
#define CONVERT_FEATURES(type, map, is_status, bitmap) \
|
|
({ \
|
|
({ \
|
|
type *list = NULL; \
|
|
type *list = NULL; \
|
|
@@ -627,6 +634,12 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
|
|
features->dev_features =
|
|
features->dev_features =
|
|
CONVERT_FEATURES(strList, virtio_rng_feature_map, 0, bitmap);
|
|
CONVERT_FEATURES(strList, virtio_rng_feature_map, 0, bitmap);
|
|
break;
|
|
break;
|
|
|
|
+#endif
|
|
|
|
+#ifdef CONFIG_VHOST_USER_GPIO
|
|
|
|
+ case VIRTIO_ID_GPIO:
|
|
|
|
+ features->dev_features =
|
|
|
|
+ CONVERT_FEATURES(strList, virtio_gpio_feature_map, 0, bitmap);
|
|
|
|
+ break;
|
|
#endif
|
|
#endif
|
|
/* No features */
|
|
/* No features */
|
|
case VIRTIO_ID_9P:
|
|
case VIRTIO_ID_9P:
|
|
@@ -653,7 +666,6 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
|
|
case VIRTIO_ID_DMABUF:
|
|
case VIRTIO_ID_DMABUF:
|
|
case VIRTIO_ID_PARAM_SERV:
|
|
case VIRTIO_ID_PARAM_SERV:
|
|
case VIRTIO_ID_AUDIO_POLICY:
|
|
case VIRTIO_ID_AUDIO_POLICY:
|
|
- case VIRTIO_ID_GPIO:
|
|
|
|
break;
|
|
break;
|
|
default:
|
|
default:
|
|
g_assert_not_reached();
|
|
g_assert_not_reached();
|
|
@@ -667,70 +679,43 @@ VirtioDeviceFeatures *qmp_decode_features(uint16_t device_id, uint64_t bitmap)
|
|
return features;
|
|
return features;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int query_dev_child(Object *child, void *opaque)
|
|
|
|
+{
|
|
|
|
+ VirtioInfoList **vdevs = opaque;
|
|
|
|
+ Object *dev = object_dynamic_cast(child, TYPE_VIRTIO_DEVICE);
|
|
|
|
+ if (dev != NULL && DEVICE(dev)->realized) {
|
|
|
|
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
|
|
|
+ VirtioInfo *info = g_new(VirtioInfo, 1);
|
|
|
|
+
|
|
|
|
+ /* Get canonical path & name of device */
|
|
|
|
+ info->path = object_get_canonical_path(dev);
|
|
|
|
+ info->name = g_strdup(vdev->name);
|
|
|
|
+ QAPI_LIST_PREPEND(*vdevs, info);
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
VirtioInfoList *qmp_x_query_virtio(Error **errp)
|
|
VirtioInfoList *qmp_x_query_virtio(Error **errp)
|
|
{
|
|
{
|
|
- VirtioInfoList *list = NULL;
|
|
|
|
- VirtioInfo *node;
|
|
|
|
- VirtIODevice *vdev;
|
|
|
|
|
|
+ VirtioInfoList *vdevs = NULL;
|
|
|
|
|
|
- QTAILQ_FOREACH(vdev, &virtio_list, next) {
|
|
|
|
- DeviceState *dev = DEVICE(vdev);
|
|
|
|
- Error *err = NULL;
|
|
|
|
- QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err);
|
|
|
|
-
|
|
|
|
- if (err == NULL) {
|
|
|
|
- GString *is_realized = qobject_to_json_pretty(obj, true);
|
|
|
|
- /* virtio device is NOT realized, remove it from list */
|
|
|
|
- if (!strncmp(is_realized->str, "false", 4)) {
|
|
|
|
- QTAILQ_REMOVE(&virtio_list, vdev, next);
|
|
|
|
- } else {
|
|
|
|
- node = g_new(VirtioInfo, 1);
|
|
|
|
- node->path = g_strdup(dev->canonical_path);
|
|
|
|
- node->name = g_strdup(vdev->name);
|
|
|
|
- QAPI_LIST_PREPEND(list, node);
|
|
|
|
- }
|
|
|
|
- g_string_free(is_realized, true);
|
|
|
|
- }
|
|
|
|
- qobject_unref(obj);
|
|
|
|
|
|
+ /* Query the QOM composition tree recursively for virtio devices */
|
|
|
|
+ object_child_foreach_recursive(object_get_root(), query_dev_child, &vdevs);
|
|
|
|
+ if (vdevs == NULL) {
|
|
|
|
+ error_setg(errp, "No virtio devices found");
|
|
}
|
|
}
|
|
-
|
|
|
|
- return list;
|
|
|
|
|
|
+ return vdevs;
|
|
}
|
|
}
|
|
|
|
|
|
VirtIODevice *qmp_find_virtio_device(const char *path)
|
|
VirtIODevice *qmp_find_virtio_device(const char *path)
|
|
{
|
|
{
|
|
- VirtIODevice *vdev;
|
|
|
|
-
|
|
|
|
- QTAILQ_FOREACH(vdev, &virtio_list, next) {
|
|
|
|
- DeviceState *dev = DEVICE(vdev);
|
|
|
|
-
|
|
|
|
- if (strcmp(dev->canonical_path, path) != 0) {
|
|
|
|
- continue;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- Error *err = NULL;
|
|
|
|
- QObject *obj = qmp_qom_get(dev->canonical_path, "realized", &err);
|
|
|
|
- if (err == NULL) {
|
|
|
|
- GString *is_realized = qobject_to_json_pretty(obj, true);
|
|
|
|
- /* virtio device is NOT realized, remove it from list */
|
|
|
|
- if (!strncmp(is_realized->str, "false", 4)) {
|
|
|
|
- g_string_free(is_realized, true);
|
|
|
|
- qobject_unref(obj);
|
|
|
|
- QTAILQ_REMOVE(&virtio_list, vdev, next);
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
- g_string_free(is_realized, true);
|
|
|
|
- } else {
|
|
|
|
- /* virtio device doesn't exist in QOM tree */
|
|
|
|
- QTAILQ_REMOVE(&virtio_list, vdev, next);
|
|
|
|
- qobject_unref(obj);
|
|
|
|
- return NULL;
|
|
|
|
- }
|
|
|
|
- /* device exists in QOM tree & is realized */
|
|
|
|
- qobject_unref(obj);
|
|
|
|
- return vdev;
|
|
|
|
|
|
+ /* Verify the canonical path is a realized virtio device */
|
|
|
|
+ Object *dev = object_dynamic_cast(object_resolve_path(path, NULL),
|
|
|
|
+ TYPE_VIRTIO_DEVICE);
|
|
|
|
+ if (!dev || !DEVICE(dev)->realized) {
|
|
|
|
+ return NULL;
|
|
}
|
|
}
|
|
- return NULL;
|
|
|
|
|
|
+ return VIRTIO_DEVICE(dev);
|
|
}
|
|
}
|
|
|
|
|
|
VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
|
|
VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
|
|
@@ -740,7 +725,7 @@ VirtioStatus *qmp_x_query_virtio_status(const char *path, Error **errp)
|
|
|
|
|
|
vdev = qmp_find_virtio_device(path);
|
|
vdev = qmp_find_virtio_device(path);
|
|
if (vdev == NULL) {
|
|
if (vdev == NULL) {
|
|
- error_setg(errp, "Path %s is not a VirtIODevice", path);
|
|
|
|
|
|
+ error_setg(errp, "Path %s is not a realized VirtIODevice", path);
|
|
return NULL;
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|