From: Huang Rui <ray.huang@amd.com>
To: "Christian König" <christian.koenig@amd.com>,
"Philip Yang" <Philip.Yang@amd.com>,
"Alex Deucher" <alexander.deucher@amd.com>,
"Felix Kuehling" <felix.kuehling@amd.com>,
"Simona Vetter" <simona@ffwll.ch>,
"Matthew Brost" <matthew.brost@intel.com>,
"Rodrigo Vivi" <rodrigo.vivi@intel.com>,
"Thomas Hellström" <thomas.hellstrom@linux.intel.com>,
"Danilo Krummrich" <dakr@kernel.org>,
"Alice Ryhl" <aliceryhl@google.com>,
amd-gfx@lists.freedesktop.org, dri-devel@lists.freedesktop.org
Cc: Xiaogang Chen <xiaogang.chen@amd.com>,
Oak Zeng <Oak.Zeng@amd.com>, "Jenny Liu" <Jenny-Jing.Liu@amd.com>,
Zhu Lingshan <lingshan.zhu@amd.com>,
"Honglei Huang" <honglei1.huang@amd.com>,
Junhua Shen <Junhua.Shen@amd.com>, Yiru Ma <yiru.ma@amd.com>,
Huang Rui <ray.huang@amd.com>, Honglei Huang <honghuan@amd.com>
Subject: [PATCH v9 10/18] drm/amdgpu: implement SVM initialization and lifecycle
Date: Tue, 4 Aug 2026 17:42:36 +0800 [thread overview]
Message-ID: <20260804094246.1719318-11-ray.huang@amd.com> (raw)
In-Reply-To: <20260804094246.1719318-1-ray.huang@amd.com>
From: Honglei Huang <honghuan@amd.com>
Implement amdgpu_svm.c core module:
- XNACK_OFF/ON helper macros for xnack state checks
- Static amdgpu_svm_cache_lock mutex for slab cache lifecycle
- drm_gpusvm_ops callbacks: range_alloc (kmem_cache), range_free,
invalidate (dispatches via svm->invalidate_ranges callback)
- kref-based lifecycle: amdgpu_svm_release, amdgpu_svm_put
- PASID lookup: amdgpu_svm_lookup_by_pasid
- Slab cache management: amdgpu_svm_cache_init/fini
- Ioctl operation wrappers: op_set_attr, op_get_attr, op_reset_attr
- Attribute change detection and application:
attr_change_trigger classifies changes into trigger types,
amdgpu_svm_apply_attr_change dispatches invalidate or remap
based on trigger flags and xnack state
- Hardware detection: amdgpu_svm_default_xnack_enabled per GC IP
- TLB flush: amdgpu_svm_flush_tlb_compute
- xnack mode: amdgpu_svm_init_xnack_mode validates requested mode
- Initialization: amdgpu_svm_init_with_ops (drm_gpusvm_init with
2M/64K/4K chunk sizes, attr tree, invalidate_ranges/flush_tlb
callbacks), amdgpu_svm_init_compute with xnack_mode parameter
- Teardown: amdgpu_svm_close (mark exiting, sync work),
amdgpu_svm_fini (gpusvm_fini, destroy attr tree, release ref)
Signed-off-by: Honglei Huang <honghuan@amd.com>
---
drivers/gpu/drm/amd/amdgpu/amdgpu_svm.c | 624 ++++++++++++++++++++++++
1 file changed, 624 insertions(+)
create mode 100644 drivers/gpu/drm/amd/amdgpu/amdgpu_svm.c
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_svm.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_svm.c
new file mode 100644
index 0000000000000..7dc43470037d2
--- /dev/null
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_svm.c
@@ -0,0 +1,624 @@
+// 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 <linux/sched/mm.h>
+#include <linux/uaccess.h>
+#include <linux/xarray.h>
+
+#include <drm/drm_file.h>
+
+#include "amdgpu.h"
+#include "amdgpu_ih.h"
+#include "amdgpu_reset.h"
+#include "amdgpu_svm.h"
+#include "amdgpu_svm_attr.h"
+#include "amdgpu_svm_fault.h"
+#include "amdgpu_svm_range.h"
+#include "amdgpu_vm.h"
+
+#if IS_ENABLED(CONFIG_DRM_AMDGPU_SVM)
+
+#define AMDGPU_SVM_MAX_ATTRS 64
+#define AMDGPU_SVM_DEFAULT_SVM_NOTIFIER_SIZE 512
+
+static const unsigned long amdgpu_svm_chunk_sizes[] = {
+ SZ_2M,
+ SZ_64K,
+ SZ_4K,
+};
+
+#define AMDGPU_SVM_GC_WQ_NAME "amdgpu_svm_gc"
+#define XNACK_OFF(svm) ((svm)->xnack_enabled == false)
+#define XNACK_ON(svm) ((svm)->xnack_enabled == true)
+
+/**
+ * amdgpu_svm_invalidate() - drm_gpusvm invalidate callback
+ * @gpusvm: The drm_gpusvm instance.
+ * @notifier: The GPU SVM notifier reporting the event.
+ * @mmu_range: The MMU notifier range describing the invalidation.
+ *
+ * Clamp the event to the notifier window, find the first affected range and
+ * dispatch to the driver's @invalidate_ranges handler.
+ */
+static void amdgpu_svm_invalidate(struct drm_gpusvm *gpusvm,
+ struct drm_gpusvm_notifier *notifier,
+ const struct mmu_notifier_range *mmu_range)
+{
+ struct amdgpu_svm *svm = to_amdgpu_svm(gpusvm);
+ struct drm_gpusvm_range *first;
+ uint64_t adj_start = mmu_range->start, adj_end = mmu_range->end;
+
+ amdgpu_svm_assert_in_notifier(svm);
+
+ AMDGPU_SVM_DBG(
+ "INVALIDATE: pasid=%u, gpusvm=%p, seqno=%lu, [0x%016lx-0x%016lx]-0x%lx, ev=%d\n",
+ svm->vm->pasid, &svm->gpusvm,
+ notifier->notifier.invalidate_seq,
+ mmu_range->start, mmu_range->end,
+ mmu_range->end - mmu_range->start, mmu_range->event);
+
+ if (mmu_range->event == MMU_NOTIFY_RELEASE)
+ return;
+ if (atomic_read(&svm->exiting))
+ return;
+
+ adj_start = max(drm_gpusvm_notifier_start(notifier), adj_start);
+ adj_end = min(drm_gpusvm_notifier_end(notifier), adj_end);
+
+ first = drm_gpusvm_range_find(notifier, adj_start, adj_end);
+ if (!first)
+ return;
+
+ svm->invalidate_ranges(svm, notifier, mmu_range, first,
+ adj_start, adj_end);
+}
+
+static struct drm_gpusvm_range *amdgpu_svm_range_alloc(struct drm_gpusvm *gpusvm)
+{
+ struct amdgpu_svm_range *range;
+
+ range = kzalloc(sizeof(*range), GFP_KERNEL);
+ if (!range)
+ return NULL;
+
+ INIT_LIST_HEAD(&range->work_node);
+ range->pending_start_page = ULONG_MAX;
+ return &range->base;
+}
+
+static void amdgpu_svm_range_free(struct drm_gpusvm_range *range)
+{
+ kfree(to_amdgpu_svm_range(range));
+}
+
+static const struct drm_gpusvm_ops amdgpu_gpusvm_ops = {
+ .range_alloc = amdgpu_svm_range_alloc,
+ .range_free = amdgpu_svm_range_free,
+ .invalidate = amdgpu_svm_invalidate,
+};
+
+static void amdgpu_svm_release(struct kref *ref)
+{
+ kfree(container_of(ref, struct amdgpu_svm, refcount));
+}
+
+/**
+ * amdgpu_svm_put() - Drop a reference on an SVM context
+ * @svm: The SVM context.
+ *
+ * Release a reference taken on @svm and free it once the last reference is
+ * dropped.
+ */
+void amdgpu_svm_put(struct amdgpu_svm *svm)
+{
+ if (svm)
+ kref_put(&svm->refcount, amdgpu_svm_release);
+}
+
+/**
+ * amdgpu_svm_lookup_by_pasid() - Find the SVM context for a PASID
+ * @adev: The amdgpu device.
+ * @pasid: The PASID to look up.
+ *
+ * Look up the VM bound to @pasid and return its SVM context with a reference
+ * taken. The caller must drop it with amdgpu_svm_put().
+ *
+ * Return: The referenced SVM context, or %NULL if none is bound.
+ */
+struct amdgpu_svm *
+amdgpu_svm_lookup_by_pasid(struct amdgpu_device *adev, uint32_t pasid)
+{
+ struct amdgpu_svm *svm = NULL;
+ struct amdgpu_vm *vm;
+ unsigned long irqflags;
+
+ xa_lock_irqsave(&adev->vm_manager.pasids, irqflags);
+ vm = xa_load(&adev->vm_manager.pasids, pasid);
+ if (vm && vm->svm) {
+ svm = vm->svm;
+ kref_get(&svm->refcount);
+ }
+ xa_unlock_irqrestore(&adev->vm_manager.pasids, irqflags);
+
+ return svm;
+}
+
+static int amdgpu_svm_op_set_attr(struct amdgpu_vm *vm,
+ uint64_t start,
+ uint64_t size,
+ uint32_t nattr,
+ const struct drm_amdgpu_svm_attribute *attrs)
+{
+ struct amdgpu_svm *svm = vm->svm;
+
+ amdgpu_svm_sync_work(svm);
+
+ return amdgpu_svm_attr_set(svm->attr_tree, start, size, nattr,
+ attrs);
+}
+
+static int amdgpu_svm_op_get_attr(struct amdgpu_vm *vm,
+ uint64_t start,
+ uint64_t size,
+ uint32_t nattr,
+ struct drm_amdgpu_svm_attribute *attrs)
+{
+ amdgpu_svm_sync_work(vm->svm);
+
+ return amdgpu_svm_attr_get(vm->svm->attr_tree, start, size, nattr, attrs);
+}
+
+static int amdgpu_svm_op_reset_attr(struct amdgpu_vm *vm,
+ uint64_t start, uint64_t size)
+{
+ struct amdgpu_svm *svm = vm->svm;
+ unsigned long start_page = start >> PAGE_SHIFT;
+ unsigned long last_page = (start + size - 1) >> PAGE_SHIFT;
+
+ amdgpu_svm_sync_work(svm);
+
+ return amdgpu_svm_attr_reset(svm->attr_tree,
+ start_page, last_page);
+}
+
+/**
+ * attr_change_trigger() - Classify what an attribute update changed
+ * @old_attrs: Attributes before the update.
+ * @new_attrs: Attributes after the update.
+ *
+ * Compare the two attribute sets and return an
+ * amdgpu_svm_attr_change_trigger bitmask describing which aspects changed:
+ * access, PTE flags, mapping flags, location, granularity, prefetch.
+ *
+ * Return: The trigger bitmask.
+ */
+static uint32_t
+attr_change_trigger(const struct amdgpu_svm_attrs *old_attrs,
+ const struct amdgpu_svm_attrs *new_attrs)
+{
+ uint32_t trigger = 0;
+ uint32_t changed_flags = old_attrs->flags ^ new_attrs->flags;
+
+ if (old_attrs->access != new_attrs->access)
+ trigger |= AMDGPU_SVM_ATTR_TRIGGER_ACCESS_CHANGE;
+ if (changed_flags & AMDGPU_SVM_PTE_FLAG_MASK)
+ trigger |= AMDGPU_SVM_ATTR_TRIGGER_PTE_FLAG_CHANGE;
+ if (changed_flags & AMDGPU_SVM_MAPPING_FLAG_MASK)
+ trigger |= AMDGPU_SVM_ATTR_TRIGGER_MAPPING_FLAG_CHANGE;
+ if (old_attrs->preferred_loc != new_attrs->preferred_loc ||
+ old_attrs->prefetch_loc != new_attrs->prefetch_loc)
+ trigger |= AMDGPU_SVM_ATTR_TRIGGER_LOCATION_CHANGE;
+ if (old_attrs->granularity != new_attrs->granularity)
+ trigger |= AMDGPU_SVM_ATTR_TRIGGER_GRANULARITY_CHANGE;
+ if (new_attrs->prefetch_loc != AMDGPU_SVM_LOCATION_UNDEFINED &&
+ new_attrs->prefetch_loc != AMDGPU_SVM_LOCATION_SYSMEM)
+ trigger |= AMDGPU_SVM_ATTR_TRIGGER_PREFETCH;
+
+ return trigger;
+}
+
+/**
+ * amdgpu_svm_apply_attr_change() - React to an attribute change on a range
+ * @svm: The SVM context.
+ * @old_attrs: Attributes before the change.
+ * @new_attrs: Attributes after the change.
+ * @start_page: First page of the affected interval.
+ * @last_page: Last page of the affected interval.
+ *
+ * Classify the change and act on it: when XNACK is on and the change affects
+ * existing GPU mappings, invalidate the interval; when the new attributes
+ * request a prefetch, map / remap the interval with the new attributes.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int amdgpu_svm_apply_attr_change(struct amdgpu_svm *svm,
+ const struct amdgpu_svm_attrs *old_attrs,
+ const struct amdgpu_svm_attrs *new_attrs,
+ unsigned long start_page,
+ unsigned long last_page)
+{
+ bool old_access, new_access;
+ bool needs_invalidate = false;
+ bool needs_mapping = false;
+ uint32_t trigger;
+ int ret;
+
+ amdgpu_svm_assert_locked(svm);
+
+ if (!start_page && !last_page)
+ return 0;
+
+ trigger = attr_change_trigger(old_attrs, new_attrs);
+ old_access = amdgpu_svm_attr_has_access(old_attrs->access);
+ new_access = amdgpu_svm_attr_has_access(new_attrs->access);
+ if (XNACK_ON(svm) &&
+ (trigger & AMDGPU_SVM_ATTR_TRIGGER_NEED_INVALIDATE))
+ needs_invalidate = true;
+
+ if (trigger & AMDGPU_SVM_ATTR_TRIGGER_PREFETCH)
+ needs_mapping = true;
+
+ if (!trigger && !needs_mapping)
+ return 0;
+
+ AMDGPU_SVM_DBG("attr change trigger=0x%x old=%d new=%d [0x%lx-0x%lx]-0x%lx, xnack=%d\n",
+ trigger, old_access, new_access, start_page, last_page,
+ last_page - start_page + 1,
+ svm->xnack_enabled ? 1 : 0);
+
+ if (needs_invalidate) {
+ AMDGPU_SVM_DBG("attr change invalidate [0x%lx-0x%lx]-0x%lx trigger=0x%x\n",
+ start_page, last_page,
+ last_page - start_page + 1, trigger);
+ ret = amdgpu_svm_range_invalidate_interval(svm, start_page,
+ last_page);
+ if (ret) {
+ AMDGPU_SVM_ERR(
+ "failed to invalidate range for attr change: [0x%lx-0x%lx], ret=%d\n",
+ start_page, last_page, ret);
+ return ret;
+ }
+ }
+
+ if (!needs_mapping)
+ return 0;
+
+ return amdgpu_svm_range_map_attrs(svm, new_attrs,
+ start_page << PAGE_SHIFT,
+ (last_page + 1) << PAGE_SHIFT);
+}
+
+bool amdgpu_svm_devmem_possible(struct amdgpu_svm *svm)
+{
+ if (svm->adev->apu_prefer_gtt)
+ return false;
+
+ /* TODO: add amdgpu_pagemap_capable() */
+
+ return false;
+}
+
+/**
+ * amdgpu_svm_default_xnack_enabled() - Whether XNACK defaults to on for the HW
+ * @adev: The amdgpu device.
+ *
+ * Decide the default retry fault (XNACK) policy from the GC IP version and
+ * platform constraints.
+ *
+ * Return: true if XNACK should default to enabled.
+ */
+static bool amdgpu_svm_default_xnack_enabled(struct amdgpu_device *adev)
+{
+ uint32_t gc_ver = amdgpu_ip_version(adev, GC_HWIP, 0);
+
+ if (gc_ver < IP_VERSION(9, 0, 1))
+ return false;
+ if (!amdgpu_sriov_xnack_support(adev))
+ return false;
+
+ if (adev->gmc.noretry)
+ return false;
+
+ switch (gc_ver) {
+ case IP_VERSION(9, 4, 2):
+ case IP_VERSION(9, 4, 3):
+ case IP_VERSION(9, 4, 4):
+ case IP_VERSION(9, 5, 0):
+ return true;
+ default:
+ break;
+ }
+ if (gc_ver >= IP_VERSION(10, 1, 1))
+ return false;
+
+ return true;
+}
+
+void amdgpu_svm_flush_tlb(struct amdgpu_svm *svm)
+{
+ amdgpu_vm_flush_compute_tlb(svm->adev, svm->vm, TLB_FLUSH_HEAVYWEIGHT,
+ svm->adev->gfx.xcc_mask);
+}
+
+static int amdgpu_svm_work_init(struct amdgpu_svm *svm,
+ void (*gc_work_func)(struct work_struct *));
+static void amdgpu_svm_work_fini(struct amdgpu_svm *svm);
+
+/**
+ * amdgpu_svm_init_xnack_mode() - Resolve the requested XNACK mode
+ * @adev: The amdgpu device.
+ * @mode: The requested XNACK mode.
+ * @xnack_enabled: Output, set to the resolved enable state.
+ *
+ * Validate @mode against the hardware default: DEFAULT follows the HW policy,
+ * ON is rejected if the HW does not support it, OFF always disables.
+ *
+ * Return: 0 on success, -EOPNOTSUPP if ON is unavailable, -EINVAL on a bad
+ * mode.
+ */
+static int amdgpu_svm_init_xnack_mode(struct amdgpu_device *adev,
+ enum amdgpu_svm_xnack_mode mode,
+ bool *xnack_enabled)
+{
+ bool xnack_default = amdgpu_svm_default_xnack_enabled(adev);
+
+ switch (mode) {
+ case AMDGPU_SVM_XNACK_DEFAULT:
+ *xnack_enabled = xnack_default;
+ break;
+ case AMDGPU_SVM_XNACK_ON:
+ if (!xnack_default) {
+ AMDGPU_SVM_ERR("xnack on not available (mode=%d)\n",
+ mode);
+ *xnack_enabled = xnack_default;
+ return -EOPNOTSUPP;
+ }
+ *xnack_enabled = true;
+ break;
+ case AMDGPU_SVM_XNACK_OFF:
+ *xnack_enabled = false;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/**
+ * amdgpu_svm_init_with_ops() - Initialize the SVM core with driver callbacks
+ * @svm: The SVM context to initialize.
+ * @invalidate_ranges: Callback invoked from the MMU notifier path.
+ * @gc_work_func: Work function draining the garbage collector.
+ *
+ * Set up the work queues, attribute tree and the embedded drm_gpusvm (with
+ * the 2M/64K/4K chunk sizes and the driver lock), wiring the supplied
+ * callbacks.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int amdgpu_svm_init_with_ops(struct amdgpu_svm *svm,
+ void (*invalidate_ranges)(struct amdgpu_svm *,
+ struct drm_gpusvm_notifier *,
+ const struct mmu_notifier_range *,
+ struct drm_gpusvm_range *,
+ uint64_t, uint64_t),
+ void (*gc_work_func)(struct work_struct *))
+{
+ struct amdgpu_device *adev = svm->adev;
+ int ret;
+
+ svm->invalidate_ranges = invalidate_ranges;
+
+ ret = amdgpu_svm_work_init(svm, gc_work_func);
+ if (ret)
+ return ret;
+
+ svm->attr_tree = amdgpu_svm_attr_tree_create(svm);
+ if (!svm->attr_tree) {
+ ret = -ENOMEM;
+ goto err_work_fini;
+ }
+
+ ret = drm_gpusvm_init(&svm->gpusvm, "AMDGPU SVM",
+ adev_to_drm(adev), current->mm, 0,
+ adev->vm_manager.max_pfn << AMDGPU_GPU_PAGE_SHIFT,
+ AMDGPU_SVM_DEFAULT_SVM_NOTIFIER_SIZE * SZ_1M,
+ &amdgpu_gpusvm_ops,
+ amdgpu_svm_chunk_sizes,
+ ARRAY_SIZE(amdgpu_svm_chunk_sizes));
+
+ if (ret)
+ goto err_attr_tree_destroy;
+
+ drm_gpusvm_driver_set_lock(&svm->gpusvm, &svm->svm_lock);
+
+ return 0;
+
+err_attr_tree_destroy:
+ amdgpu_svm_attr_tree_destroy(svm->attr_tree);
+err_work_fini:
+ amdgpu_svm_work_fini(svm);
+ return ret;
+}
+
+static void amdgpu_svm_gc_work_func(struct work_struct *w);
+
+/**
+ * amdgpu_svm_init_compute() - Create the SVM context for a compute VM
+ * @adev: The amdgpu device.
+ * @vm: The VM to attach the SVM context to.
+ * @xnack_mode: The requested XNACK mode.
+ *
+ * Allocate and initialize an SVM context for @vm (idempotent if one already
+ * exists), resolving the XNACK mode and wiring the compute callbacks. XNACK
+ * off is not supported yet.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+static int amdgpu_svm_init_compute(struct amdgpu_device *adev,
+ struct amdgpu_vm *vm,
+ enum amdgpu_svm_xnack_mode xnack_mode)
+{
+ struct amdgpu_svm *svm;
+ int ret;
+
+ if (vm->svm)
+ return 0;
+
+ svm = kzalloc(sizeof(*svm), GFP_KERNEL);
+ if (!svm)
+ return -ENOMEM;
+
+ kref_init(&svm->refcount);
+ svm->adev = adev;
+ svm->vm = vm;
+ svm->default_granularity = min_t(u8, amdgpu_svm_default_granularity, 0x1B);
+ atomic_set(&svm->exiting, 0);
+
+ ret = amdgpu_svm_init_xnack_mode(adev, xnack_mode,
+ &svm->xnack_enabled);
+ if (ret)
+ goto err_free;
+
+ if (svm->xnack_enabled) {
+ ret = amdgpu_svm_init_with_ops(svm,
+ amdgpu_svm_range_invalidate,
+ amdgpu_svm_gc_work_func);
+ } else {
+ AMDGPU_SVM_ERR("xnack off is not supported yet\n");
+ ret = -EOPNOTSUPP;
+ }
+
+ if (ret)
+ goto err_free;
+
+ AMDGPU_SVM_DBG("AMDGPU SVM initialized: default granularity 0x%lx bytes, xnack: %s\n",
+ 1UL << (svm->default_granularity + PAGE_SHIFT),
+ svm->xnack_enabled ? "enabled" : "disabled");
+
+ vm->svm = svm;
+ return 0;
+
+err_free:
+ kfree(svm);
+ return ret;
+}
+
+/**
+ * amdgpu_svm_init() - Initialize SVM for a VM
+ * @adev: The amdgpu device.
+ * @vm: The VM to enable SVM on.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int amdgpu_svm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm)
+{
+ /* graphics svm init maybe different */
+
+ return amdgpu_svm_init_compute(adev, vm, AMDGPU_SVM_XNACK_DEFAULT);
+}
+
+/**
+ * amdgpu_svm_drain_retry_fault() - Wait for retry faults to drain
+ * @adev: The amdgpu device.
+ *
+ * Wait until the interrupt handler has processed up to the current checkpoint
+ * on the relevant IH rings, so no stale retry faults remain in flight. Skips
+ * draining during a GPU reset or if the reset domain cannot be entered.
+ */
+static void amdgpu_svm_drain_retry_fault(struct amdgpu_device *adev)
+{
+ if (!adev)
+ return;
+
+ if (amdgpu_in_reset(adev))
+ return;
+
+ if (!down_read_trylock(&adev->reset_domain->sem))
+ return;
+
+ amdgpu_ih_wait_on_checkpoint_process_ts(adev,
+ adev->irq.retry_cam_enabled ?
+ &adev->irq.ih : &adev->irq.ih1);
+ if (adev->irq.retry_cam_enabled)
+ amdgpu_ih_wait_on_checkpoint_process_ts(adev,
+ &adev->irq.ih_soft);
+
+ up_read(&adev->reset_domain->sem);
+}
+
+/**
+ * amdgpu_svm_close() - Begin SVM teardown for a VM
+ * @vm: The VM whose SVM context is closing.
+ *
+ * Mark the context as exiting (once), flush pending GC work and drain
+ * in-flight retry faults. Safe to call on a VM without an SVM context.
+ */
+void amdgpu_svm_close(struct amdgpu_vm *vm)
+{
+ struct amdgpu_svm *svm = vm->svm;
+
+ if (!svm)
+ return;
+
+ if (atomic_xchg(&svm->exiting, 1))
+ return;
+
+ amdgpu_svm_sync_work(svm);
+ amdgpu_svm_drain_retry_fault(svm->adev);
+}
+
+/**
+ * amdgpu_svm_fini() - Finalize and release a VM's SVM context
+ * @vm: The VM whose SVM context is being torn down.
+ *
+ * Close the context, tear down the embedded drm_gpusvm under the SVM lock,
+ * destroy the attribute tree and work queues, and drop the context
+ * reference. Safe to call on a VM without an SVM context.
+ */
+void amdgpu_svm_fini(struct amdgpu_vm *vm)
+{
+ struct amdgpu_svm *svm = vm->svm;
+
+ if (!svm)
+ return;
+
+ amdgpu_svm_close(vm);
+ amdgpu_svm_lock(svm);
+ drm_gpusvm_fini(&svm->gpusvm);
+ amdgpu_svm_unlock(svm);
+
+ amdgpu_svm_attr_tree_destroy(svm->attr_tree);
+ amdgpu_svm_work_fini(svm);
+ vm->svm = NULL;
+ amdgpu_svm_put(svm);
+}
+
+bool amdgpu_svm_is_enabled(struct amdgpu_vm *vm)
+{
+ return vm->svm != NULL;
+}
+
+#endif /* CONFIG_DRM_AMDGPU_SVM */
--
2.53.0
next prev parent reply other threads:[~2026-08-04 9:44 UTC|newest]
Thread overview: 31+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-04 9:42 [PATCH v9 00/18] drm/amdgpu: AMDGPU SVM support based on DRM (Phase 1: single GPU, XNACK on) Huang Rui
2026-08-04 9:42 ` [PATCH v9 01/18] drm/amdgpu: add SVM ioctl UAPI definitions Huang Rui
2026-08-11 10:58 ` Christian König
2026-08-11 13:42 ` Huang, Honglei
2026-08-04 9:42 ` [PATCH v9 02/18] drm/amdgpu: add SVM core header and VM integration Huang Rui
2026-08-11 11:02 ` Christian König
2026-08-11 14:06 ` Huang, Honglei
2026-08-12 8:36 ` Christian König
2026-08-12 9:55 ` Huang, Honglei
2026-08-12 12:16 ` Christian König
2026-08-12 13:36 ` Huang Rui
2026-08-13 9:16 ` Huang, Honglei
2026-08-25 7:42 ` Honglei Huang
2026-08-27 6:36 ` Christian König
2026-08-27 7:12 ` Huang, Honglei
2026-08-04 9:42 ` [PATCH v9 03/18] drm/amdgpu: implement SVM attribute tree and helper functions Huang Rui
2026-08-04 9:42 ` [PATCH v9 04/18] drm/amdgpu: implement SVM attribute set/get/clear operations Huang Rui
2026-08-04 9:42 ` [PATCH v9 05/18] drm/amdgpu: add SVM range types and work queue interface Huang Rui
2026-08-04 9:42 ` [PATCH v9 06/18] drm/amdgpu/gmc: add get_svm_pte_flags callback Huang Rui
2026-08-04 9:42 ` [PATCH v9 07/18] drm/amdgpu: implement SVM range GPU mapping core Huang Rui
2026-08-04 9:42 ` [PATCH v9 08/18] drm/amdgpu: implement SVM range notifier and GC helpers Huang Rui
2026-08-04 9:42 ` [PATCH v9 09/18] drm/amdgpu: add SVM notifier invalidate callback and checkpoint Huang Rui
2026-08-04 9:42 ` Huang Rui [this message]
2026-08-04 9:42 ` [PATCH v9 11/18] drm/amdgpu: add SVM ioctl entry and fault handler module Huang Rui
2026-08-04 9:42 ` [PATCH v9 12/18] drm/amdgpu: integrate SVM into build system and VM fault path Huang Rui
2026-08-04 9:42 ` [PATCH v9 13/18] drm/amdgpu: add VRAM migration infrastructure for drm_pagemap Huang Rui
2026-08-04 9:42 ` [PATCH v9 14/18] drm/amdgpu: implement drm_pagemap SDMA migration callbacks Huang Rui
2026-08-04 9:42 ` [PATCH v9 15/18] drm/amdgpu: implement synchronous TTM eviction for SVM BOs Huang Rui
2026-08-04 9:42 ` [PATCH v9 16/18] drm/amdgpu: hook up ZONE_DEVICE registration in device init and reset Huang Rui
2026-08-04 9:42 ` [PATCH v9 17/18] drm/amdgpu: add SVM range migration helpers for drm_pagemap Huang Rui
2026-08-04 9:42 ` [PATCH v9 18/18] drm/amdgpu: integrate VRAM migration into SVM fault and prefetch paths Huang Rui
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260804094246.1719318-11-ray.huang@amd.com \
--to=ray.huang@amd.com \
--cc=Jenny-Jing.Liu@amd.com \
--cc=Junhua.Shen@amd.com \
--cc=Oak.Zeng@amd.com \
--cc=Philip.Yang@amd.com \
--cc=alexander.deucher@amd.com \
--cc=aliceryhl@google.com \
--cc=amd-gfx@lists.freedesktop.org \
--cc=christian.koenig@amd.com \
--cc=dakr@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=felix.kuehling@amd.com \
--cc=honghuan@amd.com \
--cc=honglei1.huang@amd.com \
--cc=lingshan.zhu@amd.com \
--cc=matthew.brost@intel.com \
--cc=rodrigo.vivi@intel.com \
--cc=simona@ffwll.ch \
--cc=thomas.hellstrom@linux.intel.com \
--cc=xiaogang.chen@amd.com \
--cc=yiru.ma@amd.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.