|
@@ -1673,6 +1673,40 @@ static const struct attribute_group virtio_net_mrg_rx_group = {
|
|
|
};
|
|
|
#endif
|
|
|
|
|
|
+static bool virtnet_fail_on_feature(struct virtio_device *vdev,
|
|
|
+ unsigned int fbit,
|
|
|
+ const char *fname, const char *dname)
|
|
|
+{
|
|
|
+ if (!virtio_has_feature(vdev, fbit))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ dev_err(&vdev->dev, "device advertises feature %s but not %s",
|
|
|
+ fname, dname);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+#define VIRTNET_FAIL_ON(vdev, fbit, dbit) \
|
|
|
+ virtnet_fail_on_feature(vdev, fbit, #fbit, dbit)
|
|
|
+
|
|
|
+static bool virtnet_validate_features(struct virtio_device *vdev)
|
|
|
+{
|
|
|
+ if (!virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ) &&
|
|
|
+ (VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_RX,
|
|
|
+ "VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
+ VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_VLAN,
|
|
|
+ "VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
+ VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_GUEST_ANNOUNCE,
|
|
|
+ "VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
+ VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_MQ, "VIRTIO_NET_F_CTRL_VQ") ||
|
|
|
+ VIRTNET_FAIL_ON(vdev, VIRTIO_NET_F_CTRL_MAC_ADDR,
|
|
|
+ "VIRTIO_NET_F_CTRL_VQ"))) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
static int virtnet_probe(struct virtio_device *vdev)
|
|
|
{
|
|
|
int i, err;
|
|
@@ -1680,6 +1714,9 @@ static int virtnet_probe(struct virtio_device *vdev)
|
|
|
struct virtnet_info *vi;
|
|
|
u16 max_queue_pairs;
|
|
|
|
|
|
+ if (!virtnet_validate_features(vdev))
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
/* Find if host supports multiqueue virtio_net device */
|
|
|
err = virtio_cread_feature(vdev, VIRTIO_NET_F_MQ,
|
|
|
struct virtio_net_config,
|