}
 
 char *uapi_key_format(char *S, unsigned int key);
-struct uverbs_api *uverbs_alloc_api(
-       const struct uverbs_object_tree_def *const *driver_specs,
-       enum rdma_driver_id driver_id);
+struct uverbs_api *uverbs_alloc_api(const struct uapi_definition *driver_def,
+                                   enum rdma_driver_id driver_id);
 void uverbs_disassociate_api_pre(struct ib_uverbs_device *uverbs_dev);
 void uverbs_disassociate_api(struct uverbs_api *uapi);
 void uverbs_destroy_api(struct uverbs_api *uapi);
                              unsigned int num_attrs);
 void uverbs_user_mmap_disassociate(struct ib_uverbs_file *ufile);
 
+extern const struct uapi_definition uverbs_def_obj_intf[];
+
 #endif /* RDMA_CORE_H */
 
 {
        struct uverbs_api *uapi;
 
-       uapi = uverbs_alloc_api(device->driver_specs, device->driver_id);
+       uapi = uverbs_alloc_api(device->driver_def, device->driver_id);
        if (IS_ERR(uapi))
                return PTR_ERR(uapi);
 
 
 
 DECLARE_UVERBS_GLOBAL_METHODS(UVERBS_OBJECT_DEVICE);
 
-DECLARE_UVERBS_OBJECT_TREE(uverbs_default_objects,
-                          &UVERBS_OBJECT(UVERBS_OBJECT_DEVICE),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_PD),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_MR),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_COMP_CHANNEL),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_CQ),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_QP),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_AH),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_MW),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_SRQ),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_FLOW),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_WQ),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_RWQ_IND_TBL),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_XRCD),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_FLOW_ACTION),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_DM),
-                          &UVERBS_OBJECT(UVERBS_OBJECT_COUNTERS));
-
-const struct uverbs_object_tree_def *uverbs_default_get_objects(void)
-{
-       return &uverbs_default_objects;
-}
+const struct uapi_definition uverbs_def_obj_intf[] = {
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DEVICE),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_PD),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_MR),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COMP_CHANNEL),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_CQ),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_QP),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_AH),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_MW),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_SRQ),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_FLOW),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_WQ),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_RWQ_IND_TBL),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_XRCD),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_FLOW_ACTION),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_DM),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(UVERBS_OBJECT_COUNTERS),
+       {}
+};
 
        return 0;
 }
 
-static int uapi_merge_tree(struct uverbs_api *uapi,
-                          const struct uverbs_object_tree_def *tree,
-                          bool is_driver)
+static int uapi_merge_obj_tree(struct uverbs_api *uapi,
+                              const struct uverbs_object_def *obj,
+                              bool is_driver)
 {
-       unsigned int i, j;
+       struct uverbs_api_object *obj_elm;
+       unsigned int i;
+       u32 obj_key;
        int rc;
 
-       if (!tree->objects)
+       obj_key = uapi_key_obj(obj->id);
+       obj_elm = uapi_add_elm(uapi, obj_key, sizeof(*obj_elm));
+       if (IS_ERR(obj_elm)) {
+               if (obj_elm != ERR_PTR(-EEXIST))
+                       return PTR_ERR(obj_elm);
+
+               /* This occurs when a driver uses ADD_UVERBS_METHODS */
+               if (WARN_ON(obj->type_attrs))
+                       return -EINVAL;
+               obj_elm = radix_tree_lookup(&uapi->radix, obj_key);
+               if (WARN_ON(!obj_elm))
+                       return -EINVAL;
+       } else {
+               obj_elm->type_attrs = obj->type_attrs;
+               if (obj->type_attrs) {
+                       obj_elm->type_class = obj->type_attrs->type_class;
+                       /*
+                        * Today drivers are only permitted to use idr_class
+                        * types. They cannot use FD types because we
+                        * currently have no way to revoke the fops pointer
+                        * after device disassociation.
+                        */
+                       if (WARN_ON(is_driver && obj->type_attrs->type_class !=
+                                                        &uverbs_idr_class))
+                               return -EINVAL;
+               }
+       }
+
+       if (!obj->methods)
                return 0;
 
-       for (i = 0; i != tree->num_objects; i++) {
-               const struct uverbs_object_def *obj = (*tree->objects)[i];
-               struct uverbs_api_object *obj_elm;
-               u32 obj_key;
+       for (i = 0; i != obj->num_methods; i++) {
+               const struct uverbs_method_def *method = (*obj->methods)[i];
 
-               if (!obj)
+               if (!method)
                        continue;
 
-               obj_key = uapi_key_obj(obj->id);
-               obj_elm = uapi_add_elm(uapi, obj_key, sizeof(*obj_elm));
-               if (IS_ERR(obj_elm)) {
-                       if (obj_elm != ERR_PTR(-EEXIST))
-                               return PTR_ERR(obj_elm);
+               rc = uapi_merge_method(uapi, obj_elm, obj_key, method,
+                                      is_driver);
+               if (rc)
+                       return rc;
+       }
 
-                       /* This occurs when a driver uses ADD_UVERBS_METHODS */
-                       if (WARN_ON(obj->type_attrs))
-                               return -EINVAL;
-                       obj_elm = radix_tree_lookup(&uapi->radix, obj_key);
-                       if (WARN_ON(!obj_elm))
-                               return -EINVAL;
-               } else {
-                       obj_elm->type_attrs = obj->type_attrs;
-                       if (obj->type_attrs) {
-                               obj_elm->type_class =
-                                       obj->type_attrs->type_class;
-                               /*
-                                * Today drivers are only permitted to use
-                                * idr_class types. They cannot use FD types
-                                * because we currently have no way to revoke
-                                * the fops pointer after device
-                                * disassociation.
-                                */
-                               if (WARN_ON(is_driver &&
-                                           obj->type_attrs->type_class !=
-                                                   &uverbs_idr_class))
-                                       return -EINVAL;
-                       }
-               }
+       return 0;
+}
+
+static int uapi_merge_def(struct uverbs_api *uapi,
+                         const struct uapi_definition *def_list,
+                         bool is_driver)
+{
+       const struct uapi_definition *def = def_list;
+       int rc;
+
+       if (!def_list)
+               return 0;
 
-               if (!obj->methods)
+       for (;; def++) {
+               switch ((enum uapi_definition_kind)def->kind) {
+               case UAPI_DEF_CHAIN:
+                       rc = uapi_merge_def(uapi, def->chain, is_driver);
+                       if (rc)
+                               return rc;
                        continue;
 
-               for (j = 0; j != obj->num_methods; j++) {
-                       const struct uverbs_method_def *method =
-                               (*obj->methods)[j];
-                       if (!method)
-                               continue;
+               case UAPI_DEF_CHAIN_OBJ_TREE:
+                       if (WARN_ON(def->object_start.object_id !=
+                                   def->chain_obj_tree->id))
+                               return -EINVAL;
 
-                       rc = uapi_merge_method(uapi, obj_elm, obj_key, method,
-                                              is_driver);
+                       rc = uapi_merge_obj_tree(uapi, def->chain_obj_tree,
+                                                is_driver);
                        if (rc)
                                return rc;
+                       continue;
+
+               case UAPI_DEF_END:
+                       return 0;
                }
+               WARN_ON(true);
+               return -EINVAL;
        }
-
-       return 0;
 }
 
 static int
        kfree(uapi);
 }
 
-struct uverbs_api *uverbs_alloc_api(
-       const struct uverbs_object_tree_def *const *driver_specs,
-       enum rdma_driver_id driver_id)
+static const struct uapi_definition uverbs_core_api[] = {
+       UAPI_DEF_CHAIN(uverbs_def_obj_intf),
+       {},
+};
+
+struct uverbs_api *uverbs_alloc_api(const struct uapi_definition *driver_def,
+                                   enum rdma_driver_id driver_id)
 {
        struct uverbs_api *uapi;
        int rc;
        INIT_RADIX_TREE(&uapi->radix, GFP_KERNEL);
        uapi->driver_id = driver_id;
 
-       rc = uapi_merge_tree(uapi, uverbs_default_get_objects(), false);
+       rc = uapi_merge_def(uapi, uverbs_core_api, false);
+       if (rc)
+               goto err;
+       rc = uapi_merge_def(uapi, driver_def, true);
        if (rc)
                goto err;
-
-       for (; driver_specs && *driver_specs; driver_specs++) {
-               rc = uapi_merge_tree(uapi, *driver_specs, true);
-               if (rc)
-                       goto err;
-       }
 
        rc = uapi_finalize(uapi);
        if (rc)
 
                            &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_UMEM_REG),
                            &UVERBS_METHOD(MLX5_IB_METHOD_DEVX_UMEM_DEREG));
 
-DECLARE_UVERBS_OBJECT_TREE(devx_objects,
-                          &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX),
-                          &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_OBJ),
-                          &UVERBS_OBJECT(MLX5_IB_OBJECT_DEVX_UMEM));
-
-const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree(void)
-{
-       return &devx_objects;
-}
+const struct uapi_definition mlx5_ib_devx_defs[] = {
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(MLX5_IB_OBJECT_DEVX),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(MLX5_IB_OBJECT_DEVX_OBJ),
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(MLX5_IB_OBJECT_DEVX_UMEM),
+       {},
+};
 
                            &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_CREATE),
                            &UVERBS_METHOD(MLX5_IB_METHOD_FLOW_MATCHER_DESTROY));
 
-DECLARE_UVERBS_OBJECT_TREE(flow_objects,
-                          &UVERBS_OBJECT(MLX5_IB_OBJECT_FLOW_MATCHER));
-
-int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root)
-{
-       int i = 0;
-
-       root[i++] = &flow_objects;
-       root[i++] = &mlx5_ib_fs;
-       root[i++] = &mlx5_ib_flow_actions;
-
-       return i;
-}
+const struct uapi_definition mlx5_ib_flow_defs[] = {
+       UAPI_DEF_CHAIN_OBJ_TREE_NAMED(MLX5_IB_OBJECT_FLOW_MATCHER),
+       UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW, &mlx5_ib_fs),
+       UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW_ACTION,
+                               &mlx5_ib_flow_actions),
+       {},
+};
 
        UVERBS_ATTR_FLAGS_IN(MLX5_IB_ATTR_CREATE_FLOW_ACTION_FLAGS,
                             enum mlx5_ib_uapi_flow_action_flags));
 
+static const struct uapi_definition mlx5_ib_defs[] = {
+#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
+       UAPI_DEF_CHAIN(mlx5_ib_flow_defs),
+#endif
+
+       UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_FLOW_ACTION,
+                               &mlx5_ib_flow_action),
+       UAPI_DEF_CHAIN_OBJ_TREE(UVERBS_OBJECT_DM, &mlx5_ib_dm),
+       {}
+};
+
 static int populate_specs_root(struct mlx5_ib_dev *dev)
 {
-       const struct uverbs_object_tree_def **trees = dev->driver_trees;
-       size_t num_trees = 0;
-
-       trees[num_trees++] = &mlx5_ib_flow_action;
-       trees[num_trees++] = &mlx5_ib_dm;
+       struct uapi_definition *defs = dev->driver_defs;
 
+#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
        if (MLX5_CAP_GEN_64(dev->mdev, general_obj_types) &
            MLX5_GENERAL_OBJ_TYPES_CAP_UCTX)
-               trees[num_trees++] = mlx5_ib_get_devx_tree();
+               *defs++ = (struct uapi_definition)UAPI_DEF_CHAIN(
+                       mlx5_ib_devx_defs);
+#endif
 
-       num_trees += mlx5_ib_get_flow_trees(trees + num_trees);
+       *defs++ = (struct uapi_definition)UAPI_DEF_CHAIN(mlx5_ib_defs);
+       *defs++ = (struct uapi_definition){};
+       WARN_ON(defs - dev->driver_defs >= ARRAY_SIZE(dev->driver_defs));
 
-       WARN_ON(num_trees >= ARRAY_SIZE(dev->driver_trees));
-       trees[num_trees] = NULL;
-       dev->ib_dev.driver_specs = trees;
+       if (IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS))
+               dev->ib_dev.driver_def = dev->driver_defs;
 
        return 0;
 }
 
 
 struct mlx5_ib_dev {
        struct ib_device                ib_dev;
-       const struct uverbs_object_tree_def *driver_trees[7];
+       struct uapi_definition          driver_defs[7];
        struct mlx5_core_dev            *mdev;
        struct mlx5_roce                roce[MLX5_MAX_PORTS];
        int                             num_ports;
 int mlx5_ib_devx_create(struct mlx5_ib_dev *dev);
 void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid);
 const struct uverbs_object_tree_def *mlx5_ib_get_devx_tree(void);
+extern const struct uapi_definition mlx5_ib_devx_defs[];
+extern const struct uapi_definition mlx5_ib_flow_defs[];
 struct mlx5_ib_flow_handler *mlx5_ib_raw_fs_rule_add(
        struct mlx5_ib_dev *dev, struct mlx5_ib_flow_matcher *fs_matcher,
        struct mlx5_flow_act *flow_act, void *cmd_in, int inlen,
        int dest_id, int dest_type);
 bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id, int *dest_type);
-int mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root);
 void mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction);
 #else
 static inline int
 mlx5_ib_devx_create(struct mlx5_ib_dev *dev) { return -EOPNOTSUPP; };
 static inline void mlx5_ib_devx_destroy(struct mlx5_ib_dev *dev, u16 uid) {}
-static inline const struct uverbs_object_tree_def *
-mlx5_ib_get_devx_tree(void) { return NULL; }
 static inline bool mlx5_ib_devx_is_flow_dest(void *obj, int *dest_id,
                                             int *dest_type)
 {
        return false;
 }
-static inline int
-mlx5_ib_get_flow_trees(const struct uverbs_object_tree_def **root)
-{
-       return 0;
-}
 static inline void
 mlx5_ib_destroy_flow_action_raw(struct mlx5_ib_flow_action *maction)
 {
 
        const struct cpumask *(*get_vector_affinity)(struct ib_device *ibdev,
                                                     int comp_vector);
 
-       const struct uverbs_object_tree_def *const *driver_specs;
+       const struct uapi_definition   *driver_def;
        enum rdma_driver_id             driver_id;
 };
 
 
        const struct uverbs_method_def * const (*methods)[];
 };
 
-struct uverbs_object_tree_def {
-       size_t                                   num_objects;
-       const struct uverbs_object_def * const (*objects)[];
+enum uapi_definition_kind {
+       UAPI_DEF_END = 0,
+       UAPI_DEF_CHAIN_OBJ_TREE,
+       UAPI_DEF_CHAIN,
 };
 
+struct uapi_definition {
+       u8 kind;
+       union {
+               struct {
+                       u16 object_id;
+               } object_start;
+       };
+
+       union {
+               const struct uapi_definition *chain;
+               const struct uverbs_object_def *chain_obj_tree;
+       };
+};
+
+/* Include another struct uapi_definition in this one */
+#define UAPI_DEF_CHAIN(_def_var)                                               \
+       {                                                                      \
+               .kind = UAPI_DEF_CHAIN, .chain = _def_var,                     \
+       }
+
+/* Temporary until the tree base description is replaced */
+#define UAPI_DEF_CHAIN_OBJ_TREE(_object_enum, _object_ptr)                     \
+       {                                                                      \
+               .kind = UAPI_DEF_CHAIN_OBJ_TREE,                               \
+               .object_start = { .object_id = _object_enum },                 \
+               .chain_obj_tree = _object_ptr,                                 \
+       }
+#define UAPI_DEF_CHAIN_OBJ_TREE_NAMED(_object_enum, ...)                       \
+       UAPI_DEF_CHAIN_OBJ_TREE(_object_enum, &UVERBS_OBJECT(_object_enum)),   \
+               ##__VA_ARGS__
+
 /*
  * =======================================
  *     Attribute Specifications
                            UVERBS_ATTR_MIN_SIZE(0),                           \
                            UA_OPTIONAL)
 
-/*
- * =======================================
- *     Declaration helpers
- * =======================================
- */
-
-#define DECLARE_UVERBS_OBJECT_TREE(_name, ...)                                 \
-       static const struct uverbs_object_def *const _name##_ptr[] = {         \
-               __VA_ARGS__,                                                   \
-       };                                                                     \
-       static const struct uverbs_object_tree_def _name = {                   \
-               .num_objects = ARRAY_SIZE(_name##_ptr),                        \
-               .objects = &_name##_ptr,                                       \
-       }
-
 /* =================================================
  *              Parsing infrastructure
  * =================================================
 
 #define ADD_UVERBS_METHODS(_name, _object_id, ...)                             \
        static const struct uverbs_method_def *const UVERBS_OBJECT_METHODS(    \
                _object_id)[] = { __VA_ARGS__ };                               \
-       static const struct uverbs_object_def _name##_struct = {               \
+       static const struct uverbs_object_def _name = {                        \
                .id = _object_id,                                              \
                .num_methods = ARRAY_SIZE(UVERBS_OBJECT_METHODS(_object_id)),  \
                .methods = &UVERBS_OBJECT_METHODS(_object_id)                  \
-       };                                                                     \
-       static const struct uverbs_object_def *const _name##_ptrs[] = {        \
-               &_name##_struct,                                               \
-       };                                                                     \
-       static const struct uverbs_object_tree_def _name = {                   \
-               .num_objects = 1,                                              \
-               .objects = &_name##_ptrs,                                      \
-       }
+       };
 
 /* Used by drivers to declare a complete parsing tree for a single method that
  * differs only in having additional driver specific attributes.
 
 #include <rdma/uverbs_ioctl.h>
 #include <rdma/ib_user_ioctl_verbs.h>
 
-#if IS_ENABLED(CONFIG_INFINIBAND_USER_ACCESS)
-const struct uverbs_object_tree_def *uverbs_default_get_objects(void);
-#else
-static inline const struct uverbs_object_tree_def *uverbs_default_get_objects(void)
-{
-       return NULL;
-}
-#endif
-
 /* Returns _id, or causes a compile error if _id is not a u32.
  *
  * The uobj APIs should only be used with the write based uAPI to access