@@ -11,10 +11,54 @@
#include "hw/virtio/vhost-shadow-virtqueue.h"
#include "qemu/error-report.h"
+#include "qapi/error.h"
#include "qemu/main-loop.h"
#include "linux-headers/linux/vhost.h"
/**
+ * Validate the transport device features that both guests can use with the SVQ
+ * and SVQs can use with the device.
+ *
+ * @dev_features: The features
+ * @errp: Error pointer
+ */
+bool vhost_svq_valid_features(uint64_t features, Error **errp)
+{
+ bool ok = true;
+ uint64_t svq_features = features;
+
+ for (uint64_t b = VIRTIO_TRANSPORT_F_START; b <= VIRTIO_TRANSPORT_F_END;
+ ++b) {
+ switch (b) {
+ case VIRTIO_F_ANY_LAYOUT:
+ continue;
+
+ case VIRTIO_F_ACCESS_PLATFORM:
+ /* SVQ trust in the host's IOMMU to translate addresses */
+ case VIRTIO_F_VERSION_1:
+ /* SVQ trust that the guest vring is little endian */
+ if (!(svq_features & BIT_ULL(b))) {
+ set_bit(b, &svq_features);
+ ok = false;
+ }
+ continue;
+
+ default:
+ if (svq_features & BIT_ULL(b)) {
+ clear_bit(b, &svq_features);
+ ok = false;
+ }
+ }
+ }
+
+ if (!ok) {
+ error_setg(errp, "SVQ Invalid device feature flags, offer: 0x%"PRIx64
+ ", ok: 0x%"PRIx64, features, svq_features);
+ }
+ return ok;
+}
+
+/**
* Forward guest notifications.
*
* @n: guest kick event notifier, the one that guest set to notify svq.
@@ -33,6 +33,8 @@ typedef struct VhostShadowVirtqueue {
EventNotifier svq_call;
} VhostShadowVirtqueue;
+bool vhost_svq_valid_features(uint64_t features, Error **errp);
+
void vhost_svq_set_svq_kick_fd(VhostShadowVirtqueue *svq, int svq_kick_fd);
void vhost_svq_set_svq_call_fd(VhostShadowVirtqueue *svq, int call_fd);
@@ -348,11 +348,26 @@ static int vhost_vdpa_init_svq(struct vhost_dev *hdev, struct vhost_vdpa *v,
Error **errp)
{
g_autoptr(GPtrArray) shadow_vqs = NULL;
+ uint64_t dev_features, svq_features;
+ int r;
+ bool ok;
if (!v->shadow_vqs_enabled) {
return 0;
}
+ r = hdev->vhost_ops->vhost_get_features(hdev, &dev_features);
+ if (r != 0) {
+ error_setg_errno(errp, -r, "Can't get vdpa device features");
+ return r;
+ }
+
+ svq_features = dev_features;
+ ok = vhost_svq_valid_features(svq_features, errp);
+ if (unlikely(!ok)) {
+ return -1;
+ }
+
shadow_vqs = g_ptr_array_new_full(hdev->nvqs, vhost_svq_free);
for (unsigned n = 0; n < hdev->nvqs; ++n) {
g_autoptr(VhostShadowVirtqueue) svq = vhost_svq_new();