On 6/12/26 11:09, Huang Rui wrote:
> From: Honglei Huang <[email protected]>
> 
> Implement attribute tree foundations in amdgpu_svm_attr.c:
> - Slab cache management: amdgpu_svm_attr_cache_init/fini

That's superflous as far as I can see. Why is not simply kmalloc used?

> - Default attribute initialization: amdgpu_svm_attr_set_default
> - Device memory and VRAM preference helpers
> - VMA validity checker: amdgpu_svm_check_vma
> - Attribute equality comparison: attr_equal
> - Interval tree CRUD operations: find, get_bounds,
>   alloc, insert, and remove
> - attr_set_interval helper for range boundary updates

You need to squash that patch together with the one who adds the header.

> 
> Signed-off-by: Honglei Huang <[email protected]>
> ---
>  drivers/gpu/drm/amd/amdgpu/amdgpu_svm_attr.c | 234 +++++++++++++++++++
>  1 file changed, 234 insertions(+)
>  create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_svm_attr.c
> 
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_svm_attr.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_svm_attr.c
> new file mode 100644
> index 0000000000000..ba09aa3c3fe4d
> --- /dev/null
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_svm_attr.c
> @@ -0,0 +1,234 @@
> +// SPDX-License-Identifier: GPL-2.0 OR MIT
> +/*
> + * Copyright 2026 Advanced Micro Devices, Inc.
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a
> + * copy of this software and associated documentation files (the "Software"),
> + * to deal in the Software without restriction, including without limitation
> + * the rights to use, copy, modify, merge, publish, distribute, sublicense,
> + * and/or sell copies of the Software, and to permit persons to whom the
> + * Software is furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
> + * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
> + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
> + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
> + * OTHER DEALINGS IN THE SOFTWARE.
> + *
> + */
> +
> +#include "amdgpu_svm.h"
> +#include "amdgpu_svm_attr.h"
> +#include "amdgpu.h"
> +
> +#include <linux/err.h>
> +#include <linux/errno.h>
> +#include <linux/gfp.h>
> +#include <linux/lockdep.h>
> +#include <linux/minmax.h>
> +#include <linux/mm.h>
> +#include <linux/slab.h>
> +
> +static struct kmem_cache *amdgpu_svm_attr_range_cache;
> +
> +struct attr_set_ctx {
> +     struct amdgpu_svm_attrs old_attrs;
> +     struct amdgpu_svm_attrs new_attrs;
> +     unsigned long start_page;
> +     unsigned long last_page;
> +};
> +
> +struct attr_get_ctx {
> +     int32_t preferred_loc;
> +     int32_t prefetch_loc;
> +     enum amdgpu_ioctl_svm_access access;
> +     uint32_t granularity;
> +     uint32_t flags_and;
> +     bool has_range;
> +};
> +
> +bool amdgpu_svm_attr_prefer_vram(const struct amdgpu_svm_attrs *attrs)
> +{
> +     if (attrs->preferred_loc != AMDGPU_SVM_LOCATION_UNDEFINED &&
> +         attrs->preferred_loc != AMDGPU_SVM_LOCATION_SYSMEM)
> +             return true;
> +
> +     if (attrs->prefetch_loc != AMDGPU_SVM_LOCATION_UNDEFINED &&
> +         attrs->prefetch_loc != AMDGPU_SVM_LOCATION_SYSMEM)
> +             return true;
> +
> +     return false;
> +}
> +
> +struct vm_area_struct *amdgpu_svm_check_vma(struct mm_struct *mm,
> +                                     unsigned long addr)
> +{
> +     const unsigned long flags = VM_IO | VM_PFNMAP | VM_MIXEDMAP;

That needs a better name.

> +     struct vm_area_struct *vma = vma_lookup(mm, addr);
> +
> +     if (!vma)
> +             return ERR_PTR(-EFAULT);
> +
> +     if (vma->vm_flags & flags)
> +             return ERR_PTR(-EOPNOTSUPP);
> +
> +     return vma;
> +}
> +
> +int amdgpu_svm_attr_cache_init(void)
> +{
> +     amdgpu_svm_attr_range_cache = AMDGPU_SVM_KMEM_CACHE_CREATE(
> +                             "amdgpu_svm_attr_range_cache", struct 
> amdgpu_svm_attr_range);
> +     if (!amdgpu_svm_attr_range_cache)
> +             return -ENOMEM;
> +
> +     return 0;
> +}
> +
> +void amdgpu_svm_attr_cache_fini(void)
> +{
> +     AMDGPU_SVM_KMEM_CACHE_DESTROY(amdgpu_svm_attr_range_cache);
> +}
> +
> +static void attr_set_interval(struct amdgpu_svm_attr_range *range,
> +                             unsigned long start_page,
> +                             unsigned long last_page)
> +{
> +     range->it_node.start = start_page;
> +     range->it_node.last = last_page;
> +}
> +
> +void amdgpu_svm_attr_set_default(struct amdgpu_svm *svm,
> +                              struct amdgpu_svm_attrs *attrs)
> +{
> +     attrs->preferred_loc = AMDGPU_SVM_LOCATION_UNDEFINED;
> +     attrs->prefetch_loc = AMDGPU_SVM_LOCATION_UNDEFINED;
> +     attrs->granularity = svm->default_granularity;
> +     attrs->flags = AMDGPU_SVM_ATTR_BIT_HOST_ACCESS | 
> AMDGPU_SVM_ATTR_BIT_COHERENT;
> +     attrs->access = svm->xnack_enabled ?
> +             AMDGPU_SVM_ACCESS_ALLOW_MIGRATE : 
> AMDGPU_SVM_ACCESS_INACCESSIBLE;
> +}
> +
> +struct amdgpu_svm_attr_range *
> +amdgpu_svm_attr_find_locked(struct amdgpu_svm_attr_tree *attr_tree,
> +                        unsigned long page)
> +{
> +     struct interval_tree_node *node;
> +
> +     node = interval_tree_iter_first(&attr_tree->tree, page, page);
> +     if (node)
> +             return container_of(node, struct amdgpu_svm_attr_range, 
> it_node);
> +
> +     return NULL;
> +}
> +
> +struct amdgpu_svm_attr_range *
> +amdgpu_svm_attr_get_bounds_locked(struct amdgpu_svm_attr_tree *attr_tree,
> +                               unsigned long page,
> +                               unsigned long *start_page,
> +                               unsigned long *last_page)
> +{
> +     struct amdgpu_svm_attr_range *attr_range;
> +     struct interval_tree_node *node;
> +     struct rb_node *rb;
> +
> +     attr_range = amdgpu_svm_attr_find_locked(attr_tree, page);
> +     if (attr_range) {
> +             *start_page = amdgpu_svm_attr_start_page(attr_range);
> +             *last_page = amdgpu_svm_attr_last_page(attr_range);
> +             return attr_range;
> +     }
> +
> +     *start_page = 0;
> +     *last_page = ULONG_MAX;
> +
> +     if (page == ULONG_MAX)
> +             return NULL;
> +
> +     node = interval_tree_iter_first(&attr_tree->tree, page + 1, ULONG_MAX);
> +     if (node) {
> +             if (node->start > page)
> +                     *last_page = node->start - 1;
> +
> +             rb = rb_prev(&node->rb);
> +             if (rb) {
> +                     node = container_of(rb, struct interval_tree_node, rb);
> +                     if (node->last < page)
> +                             *start_page = node->last + 1;
> +             }
> +     } else {
> +             rb = rb_last(&attr_tree->tree.rb_root);
> +
> +             if (rb) {
> +                     node = container_of(rb, struct interval_tree_node, rb);
> +                     if (node->last < page)
> +                             *start_page = node->last + 1;
> +             }
> +     }
> +
> +     return NULL;
> +}
> +
> +static bool attr_equal(const struct amdgpu_svm_attrs *a,
> +                              const struct amdgpu_svm_attrs *b)
> +{
> +     return a->flags == b->flags &&
> +            a->preferred_loc == b->preferred_loc &&
> +            a->prefetch_loc == b->prefetch_loc &&
> +                    a->granularity == b->granularity &&
> +                    a->access == b->access;
> +}
> +
> +struct amdgpu_svm_attr_range *
> +amdgpu_svm_attr_range_alloc(unsigned long start_page,
> +                        unsigned long last_page,
> +                        const struct amdgpu_svm_attrs *attrs)
> +{
> +     struct amdgpu_svm_attr_range *range;
> +
> +     range = kmem_cache_zalloc(amdgpu_svm_attr_range_cache, GFP_KERNEL);
> +     if (!range)
> +             return NULL;
> +
> +     INIT_LIST_HEAD(&range->list);
> +     attr_set_interval(range, start_page, last_page);
> +     range->attrs = *attrs;
> +     return range;
> +}
> +
> +void amdgpu_svm_attr_range_insert_locked(struct amdgpu_svm_attr_tree 
> *attr_tree,
> +                                      struct amdgpu_svm_attr_range *range)
> +{
> +     struct interval_tree_node *node;
> +     struct amdgpu_svm_attr_range *next;
> +
> +     lockdep_assert_held(&attr_tree->lock);
> +
> +     node = interval_tree_iter_first(&attr_tree->tree, 
> amdgpu_svm_attr_start_page(range),
> +                                     ULONG_MAX);
> +     if (node) {
> +             next = container_of(node, struct amdgpu_svm_attr_range, 
> it_node);
> +             list_add_tail(&range->list, &next->list);
> +     } else {
> +             list_add_tail(&range->list, &attr_tree->range_list);
> +     }
> +
> +     interval_tree_insert(&range->it_node, &attr_tree->tree);
> +}
> +
> +static void attr_remove_range_locked(struct amdgpu_svm_attr_tree *attr_tree,
> +                                       struct amdgpu_svm_attr_range *range,
> +                                       bool free_range)
> +{
> +     lockdep_assert_held(&attr_tree->lock);
> +
> +     interval_tree_remove(&range->it_node, &attr_tree->tree);
> +     list_del_init(&range->list);
> +     if (free_range)
> +             kmem_cache_free(amdgpu_svm_attr_range_cache, range);
> +}

Reply via email to