Merge tag 'amdtee-fix-for-v6.3' of https://git.linaro.org/people/jens.wiklander/linux...
[linux-2.6-microblaze.git] / drivers / vdpa / vdpa.c
index 8ef7aa1..965e325 100644 (file)
@@ -39,6 +39,11 @@ static int vdpa_dev_probe(struct device *d)
        u32 max_num, min_num = 1;
        int ret = 0;
 
+       d->dma_mask = &d->coherent_dma_mask;
+       ret = dma_set_mask_and_coherent(d, DMA_BIT_MASK(64));
+       if (ret)
+               return ret;
+
        max_num = ops->get_vq_num_max(vdev);
        if (ops->get_vq_num_min)
                min_num = ops->get_vq_num_min(vdev);
@@ -460,12 +465,28 @@ static int vdpa_nl_mgmtdev_handle_fill(struct sk_buff *msg, const struct vdpa_mg
        return 0;
 }
 
+static u64 vdpa_mgmtdev_get_classes(const struct vdpa_mgmt_dev *mdev,
+                                   unsigned int *nclasses)
+{
+       u64 supported_classes = 0;
+       unsigned int n = 0;
+
+       for (int i = 0; mdev->id_table[i].device; i++) {
+               if (mdev->id_table[i].device > 63)
+                       continue;
+               supported_classes |= BIT_ULL(mdev->id_table[i].device);
+               n++;
+       }
+       if (nclasses)
+               *nclasses = n;
+
+       return supported_classes;
+}
+
 static int vdpa_mgmtdev_fill(const struct vdpa_mgmt_dev *mdev, struct sk_buff *msg,
                             u32 portid, u32 seq, int flags)
 {
-       u64 supported_classes = 0;
        void *hdr;
-       int i = 0;
        int err;
 
        hdr = genlmsg_put(msg, portid, seq, &vdpa_nl_family, flags, VDPA_CMD_MGMTDEV_NEW);
@@ -475,14 +496,9 @@ static int vdpa_mgmtdev_fill(const struct vdpa_mgmt_dev *mdev, struct sk_buff *m
        if (err)
                goto msg_err;
 
-       while (mdev->id_table[i].device) {
-               if (mdev->id_table[i].device <= 63)
-                       supported_classes |= BIT_ULL(mdev->id_table[i].device);
-               i++;
-       }
-
        if (nla_put_u64_64bit(msg, VDPA_ATTR_MGMTDEV_SUPPORTED_CLASSES,
-                             supported_classes, VDPA_ATTR_UNSPEC)) {
+                             vdpa_mgmtdev_get_classes(mdev, NULL),
+                             VDPA_ATTR_UNSPEC)) {
                err = -EMSGSIZE;
                goto msg_err;
        }
@@ -566,13 +582,25 @@ out:
                                 BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MTU)     | \
                                 BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP))
 
+/*
+ * Bitmask for all per-device features: feature bits VIRTIO_TRANSPORT_F_START
+ * through VIRTIO_TRANSPORT_F_END are unset, i.e. 0xfffffc000fffffff for
+ * all 64bit features. If the features are extended beyond 64 bits, or new
+ * "holes" are reserved for other type of features than per-device, this
+ * macro would have to be updated.
+ */
+#define VIRTIO_DEVICE_F_MASK (~0ULL << (VIRTIO_TRANSPORT_F_END + 1) | \
+                             ((1ULL << VIRTIO_TRANSPORT_F_START) - 1))
+
 static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *info)
 {
        struct vdpa_dev_set_config config = {};
        struct nlattr **nl_attrs = info->attrs;
        struct vdpa_mgmt_dev *mdev;
+       unsigned int ncls = 0;
        const u8 *macaddr;
        const char *name;
+       u64 classes;
        int err = 0;
 
        if (!info->attrs[VDPA_ATTR_DEV_NAME])
@@ -601,8 +629,26 @@ static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *i
                config.mask |= BIT_ULL(VDPA_ATTR_DEV_NET_CFG_MAX_VQP);
        }
        if (nl_attrs[VDPA_ATTR_DEV_FEATURES]) {
+               u64 missing = 0x0ULL;
+
                config.device_features =
                        nla_get_u64(nl_attrs[VDPA_ATTR_DEV_FEATURES]);
+               if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MACADDR] &&
+                   !(config.device_features & BIT_ULL(VIRTIO_NET_F_MAC)))
+                       missing |= BIT_ULL(VIRTIO_NET_F_MAC);
+               if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MTU] &&
+                   !(config.device_features & BIT_ULL(VIRTIO_NET_F_MTU)))
+                       missing |= BIT_ULL(VIRTIO_NET_F_MTU);
+               if (nl_attrs[VDPA_ATTR_DEV_NET_CFG_MAX_VQP] &&
+                   config.net.max_vq_pairs > 1 &&
+                   !(config.device_features & BIT_ULL(VIRTIO_NET_F_MQ)))
+                       missing |= BIT_ULL(VIRTIO_NET_F_MQ);
+               if (missing) {
+                       NL_SET_ERR_MSG_FMT_MOD(info->extack,
+                                              "Missing features 0x%llx for provided attributes",
+                                              missing);
+                       return -EINVAL;
+               }
                config.mask |= BIT_ULL(VDPA_ATTR_DEV_FEATURES);
        }
 
@@ -622,13 +668,33 @@ static int vdpa_nl_cmd_dev_add_set_doit(struct sk_buff *skb, struct genl_info *i
                err = PTR_ERR(mdev);
                goto err;
        }
+
        if ((config.mask & mdev->config_attr_mask) != config.mask) {
-               NL_SET_ERR_MSG_MOD(info->extack,
-                                  "All provided attributes are not supported");
+               NL_SET_ERR_MSG_FMT_MOD(info->extack,
+                                      "Some provided attributes are not supported: 0x%llx",
+                                      config.mask & ~mdev->config_attr_mask);
                err = -EOPNOTSUPP;
                goto err;
        }
 
+       classes = vdpa_mgmtdev_get_classes(mdev, &ncls);
+       if (config.mask & VDPA_DEV_NET_ATTRS_MASK &&
+           !(classes & BIT_ULL(VIRTIO_ID_NET))) {
+               NL_SET_ERR_MSG_MOD(info->extack,
+                                  "Network class attributes provided on unsupported management device");
+               err = -EINVAL;
+               goto err;
+       }
+       if (!(config.mask & VDPA_DEV_NET_ATTRS_MASK) &&
+           config.mask & BIT_ULL(VDPA_ATTR_DEV_FEATURES) &&
+           classes & BIT_ULL(VIRTIO_ID_NET) && ncls > 1 &&
+           config.device_features & VIRTIO_DEVICE_F_MASK) {
+               NL_SET_ERR_MSG_MOD(info->extack,
+                                  "Management device supports multi-class while device features specified are ambiguous");
+               err = -EINVAL;
+               goto err;
+       }
+
        err = mdev->ops->dev_add(mdev, name, &config);
 err:
        up_write(&vdpa_dev_lock);
@@ -841,18 +907,25 @@ static int vdpa_dev_net_mac_config_fill(struct sk_buff *msg, u64 features,
                        sizeof(config->mac), config->mac);
 }
 
+static int vdpa_dev_net_status_config_fill(struct sk_buff *msg, u64 features,
+                                          const struct virtio_net_config *config)
+{
+       u16 val_u16;
+
+       if ((features & BIT_ULL(VIRTIO_NET_F_STATUS)) == 0)
+               return 0;
+
+       val_u16 = __virtio16_to_cpu(true, config->status);
+       return nla_put_u16(msg, VDPA_ATTR_DEV_NET_STATUS, val_u16);
+}
+
 static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *msg)
 {
        struct virtio_net_config config = {};
        u64 features_device;
-       u16 val_u16;
 
        vdev->config->get_config(vdev, 0, &config, sizeof(config));
 
-       val_u16 = __virtio16_to_cpu(true, config.status);
-       if (nla_put_u16(msg, VDPA_ATTR_DEV_NET_STATUS, val_u16))
-               return -EMSGSIZE;
-
        features_device = vdev->config->get_device_features(vdev);
 
        if (nla_put_u64_64bit(msg, VDPA_ATTR_DEV_FEATURES, features_device,
@@ -865,6 +938,9 @@ static int vdpa_dev_net_config_fill(struct vdpa_device *vdev, struct sk_buff *ms
        if (vdpa_dev_net_mac_config_fill(msg, features_device, &config))
                return -EMSGSIZE;
 
+       if (vdpa_dev_net_status_config_fill(msg, features_device, &config))
+               return -EMSGSIZE;
+
        return vdpa_dev_net_mq_config_fill(msg, features_device, &config);
 }
 
@@ -1011,7 +1087,7 @@ static int vdpa_dev_vendor_stats_fill(struct vdpa_device *vdev,
        switch (device_id) {
        case VIRTIO_ID_NET:
                if (index > VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX) {
-                       NL_SET_ERR_MSG_MOD(info->extack, "queue index excceeds max value");
+                       NL_SET_ERR_MSG_MOD(info->extack, "queue index exceeds max value");
                        err = -ERANGE;
                        break;
                }