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); > +}
