aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--hw/net/vhost_net.c56
-rw-r--r--hw/scsi/vhost-scsi.c25
-rw-r--r--hw/virtio/vhost.c27
-rw-r--r--include/hw/virtio/vhost.h5
4 files changed, 71 insertions, 42 deletions
diff --git a/hw/net/vhost_net.c b/hw/net/vhost_net.c
index a1de2f43a0..6a9a32f56b 100644
--- a/hw/net/vhost_net.c
+++ b/hw/net/vhost_net.c
@@ -46,39 +46,41 @@ struct vhost_net {
NetClientState *nc;
};
-unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
+/* Features supported by host kernel. */
+static const int kernel_feature_bits[] = {
+ VIRTIO_F_NOTIFY_ON_EMPTY,
+ VIRTIO_RING_F_INDIRECT_DESC,
+ VIRTIO_RING_F_EVENT_IDX,
+ VIRTIO_NET_F_MRG_RXBUF,
+ VHOST_INVALID_FEATURE_BIT
+};
+
+static const int *vhost_net_get_feature_bits(struct vhost_net *net)
{
- /* Clear features not supported by host kernel. */
- if (!(net->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) {
- features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
- }
- if (!(net->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
- features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
- }
- if (!(net->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
- features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
- }
- if (!(net->dev.features & (1 << VIRTIO_NET_F_MRG_RXBUF))) {
- features &= ~(1 << VIRTIO_NET_F_MRG_RXBUF);
+ const int *feature_bits = 0;
+
+ switch (net->nc->info->type) {
+ case NET_CLIENT_OPTIONS_KIND_TAP:
+ feature_bits = kernel_feature_bits;
+ break;
+ default:
+ error_report("Feature bits not defined for this type: %d",
+ net->nc->info->type);
+ break;
}
- return features;
+
+ return feature_bits;
+}
+
+unsigned vhost_net_get_features(struct vhost_net *net, unsigned features)
+{
+ return vhost_get_features(&net->dev, vhost_net_get_feature_bits(net),
+ features);
}
void vhost_net_ack_features(struct vhost_net *net, unsigned features)
{
- net->dev.acked_features = net->dev.backend_features;
- if (features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY)) {
- net->dev.acked_features |= (1 << VIRTIO_F_NOTIFY_ON_EMPTY);
- }
- if (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
- net->dev.acked_features |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
- }
- if (features & (1 << VIRTIO_RING_F_EVENT_IDX)) {
- net->dev.acked_features |= (1 << VIRTIO_RING_F_EVENT_IDX);
- }
- if (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) {
- net->dev.acked_features |= (1 << VIRTIO_NET_F_MRG_RXBUF);
- }
+ vhost_ack_features(&net->dev, vhost_net_get_feature_bits(net), features);
}
static int vhost_net_get_fd(NetClientState *backend)
diff --git a/hw/scsi/vhost-scsi.c b/hw/scsi/vhost-scsi.c
index 668bafa72a..a12d88846f 100644
--- a/hw/scsi/vhost-scsi.c
+++ b/hw/scsi/vhost-scsi.c
@@ -24,6 +24,15 @@
#include "hw/virtio/virtio-scsi.h"
#include "hw/virtio/virtio-bus.h"
+/* Features supported by host kernel. */
+static const int kernel_feature_bits[] = {
+ VIRTIO_F_NOTIFY_ON_EMPTY,
+ VIRTIO_RING_F_INDIRECT_DESC,
+ VIRTIO_RING_F_EVENT_IDX,
+ VIRTIO_SCSI_F_HOTPLUG,
+ VHOST_INVALID_FEATURE_BIT
+};
+
static int vhost_scsi_set_endpoint(VHostSCSI *s)
{
VirtIOSCSICommon *vs = VIRTIO_SCSI_COMMON(s);
@@ -141,21 +150,7 @@ static uint32_t vhost_scsi_get_features(VirtIODevice *vdev,
{
VHostSCSI *s = VHOST_SCSI(vdev);
- /* Clear features not supported by host kernel. */
- if (!(s->dev.features & (1 << VIRTIO_F_NOTIFY_ON_EMPTY))) {
- features &= ~(1 << VIRTIO_F_NOTIFY_ON_EMPTY);
- }
- if (!(s->dev.features & (1 << VIRTIO_RING_F_INDIRECT_DESC))) {
- features &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
- }
- if (!(s->dev.features & (1 << VIRTIO_RING_F_EVENT_IDX))) {
- features &= ~(1 << VIRTIO_RING_F_EVENT_IDX);
- }
- if (!(s->dev.features & (1 << VIRTIO_SCSI_F_HOTPLUG))) {
- features &= ~(1 << VIRTIO_SCSI_F_HOTPLUG);
- }
-
- return features;
+ return vhost_get_features(&s->dev, kernel_feature_bits, features);
}
static void vhost_scsi_set_config(VirtIODevice *vdev,
diff --git a/hw/virtio/vhost.c b/hw/virtio/vhost.c
index 9e6023af36..a3e872d2f1 100644
--- a/hw/virtio/vhost.c
+++ b/hw/virtio/vhost.c
@@ -990,6 +990,33 @@ void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
assert(r >= 0);
}
+unsigned vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
+ unsigned features)
+{
+ const int *bit = feature_bits;
+ while (*bit != VHOST_INVALID_FEATURE_BIT) {
+ unsigned bit_mask = (1 << *bit);
+ if (!(hdev->features & bit_mask)) {
+ features &= ~bit_mask;
+ }
+ bit++;
+ }
+ return features;
+}
+
+void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits,
+ unsigned features)
+{
+ const int *bit = feature_bits;
+ while (*bit != VHOST_INVALID_FEATURE_BIT) {
+ unsigned bit_mask = (1 << *bit);
+ if (features & bit_mask) {
+ hdev->acked_features |= bit_mask;
+ }
+ bit++;
+ }
+}
+
/* Host notifiers must be enabled at this point. */
int vhost_dev_start(struct vhost_dev *hdev, VirtIODevice *vdev)
{
diff --git a/include/hw/virtio/vhost.h b/include/hw/virtio/vhost.h
index de24746c7e..df1f2149cc 100644
--- a/include/hw/virtio/vhost.h
+++ b/include/hw/virtio/vhost.h
@@ -25,6 +25,7 @@ typedef unsigned long vhost_log_chunk_t;
#define VHOST_LOG_PAGE 0x1000
#define VHOST_LOG_BITS (8 * sizeof(vhost_log_chunk_t))
#define VHOST_LOG_CHUNK (VHOST_LOG_PAGE * VHOST_LOG_BITS)
+#define VHOST_INVALID_FEATURE_BIT (0xff)
struct vhost_memory;
struct vhost_dev {
@@ -68,4 +69,8 @@ bool vhost_virtqueue_pending(struct vhost_dev *hdev, int n);
*/
void vhost_virtqueue_mask(struct vhost_dev *hdev, VirtIODevice *vdev, int n,
bool mask);
+unsigned vhost_get_features(struct vhost_dev *hdev, const int *feature_bits,
+ unsigned features);
+void vhost_ack_features(struct vhost_dev *hdev, const int *feature_bits,
+ unsigned features);
#endif