amd-drm-fixes-7.3-2026-09-24:

amdgpu:
 - Display ref count fix
 - Userq fixes
 - VCN 4, 5 reset fixes
 - Fixes for various error paths
 - Stack frame size fixes for various combinations of compilers and configs
 
 amdkfd:
 - Possible UAF fix
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQQgO5Idg2tXNTSZAr293/aFa7yZ2AUCarVdBwAKCRC93/aFa7yZ
 2IiRAP9QnDZ0lLR36p0yPHlMVl2opdMfkqeLkdHd6BgDn/3/mwEA780cxI7gxbFH
 LS7QLSW9L68xjdAixoUWi/UYCIG4sAQ=
 =VbtV
 -----END PGP SIGNATURE-----

Merge tag 'amd-drm-fixes-7.3-2026-09-24' of https://gitlab.freedesktop.org/drm/amdgpu/kernel into drm-fixes

amd-drm-fixes-7.3-2026-09-24:

amdgpu:
- Display ref count fix
- Userq fixes
- VCN 4, 5 reset fixes
- Fixes for various error paths
- Stack frame size fixes for various combinations of compilers and configs

amdkfd:
- Possible UAF fix

Signed-off-by: Dave Airlie <airlied@redhat.com>

From: Alex Deucher <alexander.deucher@amd.com>
Link: https://patch.msgid.link/20260924172938.634777-1-alexander.deucher@amd.com
This commit is contained in:
Dave Airlie 2026-09-25 16:54:43 +10:00
commit 0f50dab8b4
13 changed files with 87 additions and 33 deletions

View File

@ -1167,8 +1167,10 @@ int amdgpu_acpi_enumerate_xcc(void)
}
xcc_info = kzalloc_obj(struct amdgpu_acpi_xcc_info);
if (!xcc_info)
if (!xcc_info) {
acpi_dev_put(acpi_dev);
return -ENOMEM;
}
INIT_LIST_HEAD(&xcc_info->list);
xcc_info->handle = acpi_device_handle(acpi_dev);

View File

@ -1780,8 +1780,10 @@ static int amdgpu_debugfs_test_ib_show(struct seq_file *m, void *unused)
/* Avoid accidently unparking the sched thread during GPU reset */
r = down_write_killable(&adev->reset_domain->sem);
if (r)
if (r) {
pm_runtime_put_autosuspend(dev->dev);
return r;
}
/* hold on the scheduler */
for (i = 0; i < AMDGPU_MAX_RINGS; i++) {

View File

@ -68,6 +68,9 @@ amdgpu_eviction_fence_suspend_worker(struct work_struct *work)
mutex_lock(&uq_mgr->userq_mutex);
/* Fence waits are not allowed in a fence signalling critical section. */
amdgpu_userq_wait_for_signal(uq_mgr);
/*
* This is intentionally after taking the userq_mutex since we do
* allocate memory while holding this lock, but only after ensuring that

View File

@ -254,7 +254,6 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
ring->adev = adev;
ring->num_hw_submission = sched_hw_submission;
ring->sched_score = sched_score;
ring->vmid_wait = dma_fence_get_stub();
ring->idx = adev->num_rings++;
adev->rings[ring->idx] = ring;
@ -374,6 +373,7 @@ int amdgpu_ring_init(struct amdgpu_device *adev, struct amdgpu_ring *ring,
ring->max_dw = max_dw;
ring->hw_prio = hw_prio;
ring->vmid_wait = dma_fence_get_stub();
if (!ring->no_scheduler && ring->funcs->type < AMDGPU_HW_IP_NUM) {
hw_ip = ring->funcs->type;

View File

@ -184,27 +184,27 @@ static void amdgpu_userq_hang_detect_work(struct work_struct *work)
void amdgpu_userq_start_hang_detect_work(struct amdgpu_usermode_queue *queue)
{
struct amdgpu_device *adev;
unsigned long timeout_ms;
unsigned long timeout_jiffies;
adev = queue->userq_mgr->adev;
/* Determine timeout based on queue type */
switch (queue->queue_type) {
case AMDGPU_RING_TYPE_GFX:
timeout_ms = adev->gfx_timeout;
timeout_jiffies = adev->gfx_timeout;
break;
case AMDGPU_RING_TYPE_COMPUTE:
timeout_ms = adev->compute_timeout;
timeout_jiffies = adev->compute_timeout;
break;
case AMDGPU_RING_TYPE_SDMA:
timeout_ms = adev->sdma_timeout;
timeout_jiffies = adev->sdma_timeout;
break;
default:
timeout_ms = adev->gfx_timeout;
timeout_jiffies = adev->gfx_timeout;
break;
}
queue_delayed_work(adev->reset_domain->wq, &queue->hang_detect_work,
msecs_to_jiffies(timeout_ms));
timeout_jiffies);
}
void amdgpu_userq_process_fence_irq(struct amdgpu_device *adev, u32 doorbell)
@ -1272,7 +1272,7 @@ amdgpu_userq_evict_all(struct amdgpu_userq_mgr *uq_mgr)
return ret;
}
static void
void
amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
{
struct amdgpu_usermode_queue *queue;
@ -1291,8 +1291,6 @@ amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr)
void
amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr)
{
/* Wait for any pending userqueue fence work to finish */
amdgpu_userq_wait_for_signal(uq_mgr);
amdgpu_userq_evict_all(uq_mgr);
}

View File

@ -162,6 +162,7 @@ void amdgpu_userq_mgr_cancel_reset_work(struct amdgpu_device *adev);
void amdgpu_userq_mgr_cancel_resume(struct amdgpu_userq_mgr *userq_mgr);
void amdgpu_userq_mgr_fini(struct amdgpu_userq_mgr *userq_mgr);
void amdgpu_userq_wait_for_signal(struct amdgpu_userq_mgr *uq_mgr);
void amdgpu_userq_evict(struct amdgpu_userq_mgr *uq_mgr);
void amdgpu_userq_ensure_ev_fence(struct amdgpu_userq_mgr *userq_mgr,

View File

@ -2678,6 +2678,7 @@ int amdgpu_vm_init(struct amdgpu_device *adev, struct amdgpu_vm *vm,
amdgpu_bo_unref(&root_bo);
error_free_delayed:
dma_fence_put(vm->last_update);
dma_fence_put(vm->last_tlb_flush);
dma_fence_put(vm->last_unlocked);
ttm_lru_bulk_move_fini(&adev->mman.bdev, &vm->lru_bulk_move);

View File

@ -1689,7 +1689,8 @@ static int vcn_v4_0_3_reset_jpeg_pre_helper(struct amdgpu_device *adev, int inst
/* if Jobs are still pending after timeout,
* We'll handle them in the bottom helper
*/
amdgpu_fence_wait_polling(ring, wait_seq, adev->video_timeout);
amdgpu_fence_wait_polling(ring, wait_seq,
jiffies_to_usecs(adev->video_timeout));
}
return 0;

View File

@ -1335,7 +1335,8 @@ static int vcn_v5_0_1_reset_jpeg_pre_helper(struct amdgpu_device *adev, int inst
/* if Jobs are still pending after timeout,
* We'll handle them in the bottom helper
*/
amdgpu_fence_wait_polling(ring, wait_seq, adev->video_timeout);
amdgpu_fence_wait_polling(ring, wait_seq,
jiffies_to_usecs(adev->video_timeout));
}
return 0;

View File

@ -35,6 +35,7 @@
#include <linux/time.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/pseudo_fs.h>
#include <linux/ptrace.h>
#include <linux/dma-buf.h>
#include <linux/processor.h>
@ -70,18 +71,54 @@ static const struct class kfd_class = {
};
/*
* Cache the address space of the chardev on first open so that the reset
* path can drop all userspace mappings of doorbell and MMIO ranges via
* unmap_mapping_range().
* Private pseudo-filesystem for KFD, Provides a stable, module-owned
* inode whose address_space is the unmap target for all /dev/kfd
* openers during GPU reset.
*/
static struct address_space *kfd_dev_mapping;
static struct vfsmount *kfd_fs_mnt;
static int kfd_fs_cnt;
static int kfd_fs_init_fs_context(struct fs_context *fc)
{
return init_pseudo(fc, 0x4b464400 /* "KFD" */) ? 0 : -ENOMEM;
}
static struct file_system_type kfd_fs_type = {
.name = "kfd",
.init_fs_context = kfd_fs_init_fs_context,
.kill_sb = kill_anon_super,
};
static struct inode *kfd_fs_inode_new(void)
{
struct inode *inode;
int r;
r = simple_pin_fs(&kfd_fs_type, &kfd_fs_mnt, &kfd_fs_cnt);
if (r < 0)
return ERR_PTR(r);
inode = alloc_anon_inode(kfd_fs_mnt->mnt_sb);
if (IS_ERR(inode))
simple_release_fs(&kfd_fs_mnt, &kfd_fs_cnt);
return inode;
}
static void kfd_fs_inode_free(struct inode *inode)
{
if (inode) {
iput(inode);
simple_release_fs(&kfd_fs_mnt, &kfd_fs_cnt);
}
}
static struct inode *kfd_anon_inode;
void kfd_dev_unmap_mapping_range(loff_t const holebegin, loff_t const holelen)
{
struct address_space *mapping = READ_ONCE(kfd_dev_mapping);
if (mapping)
unmap_mapping_range(mapping, holebegin, holelen, 1);
if (kfd_anon_inode)
unmap_mapping_range(kfd_anon_inode->i_mapping, holebegin, holelen, 1);
}
static inline struct kfd_process_device *kfd_lock_pdd_by_id(struct kfd_process *p, __u32 gpu_id)
@ -107,6 +144,13 @@ int kfd_chardev_init(void)
{
int err = 0;
kfd_anon_inode = kfd_fs_inode_new();
if (IS_ERR(kfd_anon_inode)) {
err = PTR_ERR(kfd_anon_inode);
kfd_anon_inode = NULL;
return err;
}
kfd_char_dev_major = register_chrdev(0, kfd_dev_name, &kfd_fops);
err = kfd_char_dev_major;
if (err < 0)
@ -130,6 +174,8 @@ int kfd_chardev_init(void)
err_class_create:
unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
err_register_chrdev:
kfd_fs_inode_free(kfd_anon_inode);
kfd_anon_inode = NULL;
return err;
}
@ -138,6 +184,8 @@ void kfd_chardev_exit(void)
device_destroy(&kfd_class, MKDEV(kfd_char_dev_major, 0));
class_unregister(&kfd_class);
unregister_chrdev(kfd_char_dev_major, kfd_dev_name);
kfd_fs_inode_free(kfd_anon_inode);
kfd_anon_inode = NULL;
kfd_device = NULL;
}
@ -150,12 +198,7 @@ static int kfd_open(struct inode *inode, struct file *filep)
if (iminor(inode) != 0)
return -ENODEV;
/*
* /dev/kfd is a single chardev so all opens share one inode. Cache
* its address_space on the first open for use by the reset path.
*/
if (!READ_ONCE(kfd_dev_mapping))
cmpxchg(&kfd_dev_mapping, NULL, inode->i_mapping);
filep->f_mapping = kfd_anon_inode->i_mapping;
is_32bit_user_mode = in_compat_syscall();

View File

@ -5583,8 +5583,10 @@ static int dm_update_crtc_state(struct amdgpu_display_manager *dm,
skip_modeset:
/* Release extra reference */
if (new_stream)
if (new_stream) {
dc_stream_release(new_stream);
new_stream = NULL;
}
new_stream = NULL;
/*

View File

@ -29,14 +29,14 @@ dml_ccflags := $(CC_FLAGS_FPU)
dml_rcflags := $(CC_FLAGS_NO_FPU)
ifneq ($(CONFIG_FRAME_WARN),0)
ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y)
ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)$(CONFIG_UBSAN)),y)
ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy)
frame_warn_limit := 4096
else
frame_warn_limit := 3072
endif
else
frame_warn_limit := 2048
frame_warn_limit := 3072
endif
ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y)

View File

@ -28,14 +28,14 @@ dml2_ccflags := $(CC_FLAGS_FPU)
dml2_rcflags := $(CC_FLAGS_NO_FPU)
ifneq ($(CONFIG_FRAME_WARN),0)
ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)),y)
ifeq ($(filter y,$(CONFIG_KASAN)$(CONFIG_KCSAN)$(CONFIG_UBSAN)),y)
ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_COMPILE_TEST),yy)
frame_warn_limit := 4096
else
frame_warn_limit := 3072
endif
else
frame_warn_limit := 2056
frame_warn_limit := 3072
endif
ifeq ($(call test-lt, $(CONFIG_FRAME_WARN), $(frame_warn_limit)),y)