On 5/13/26 16:21, Kuehling, Felix wrote:
>
> On 2026-05-13 01:58, Christian König wrote:
>>
>> On 5/11/26 16:22, Yifan Zhang wrote:
>>> During Mode 1 reset, the ASIC undergoes a reset cycle and becomes
>>> temporarily
>>> inaccessible via PCIe. Any attempt to access framebuffer or MMIO registers
>>> during
>>> this window can result in uncompleted PCIe transactions, leading to NMI
>>> panics or
>>> system hangs.
>>>
>>> To prevent this, Unmap all of the applications mappings of the framebuffer
>>> and doorbell BARs before mode1 reset. Also prevent new mappings from coming
>>> in
>>> during the reset process.
>>>
>>> v2: remove inode in kfd_dev (Christian)
>>> v3: correct unmap offset (Felix), remove prevent new mappings part to avoid
>>> deadlock (Christian)
>>>
>>> Signed-off-by: Yifan Zhang <[email protected]>
>>> ---
>>> drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 22 ++++++++++++++++++++++
>>> drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h | 1 +
>>> drivers/gpu/drm/amd/amdgpu/amdgpu_device.c | 6 ++++++
>>> drivers/gpu/drm/amd/amdkfd/kfd_chardev.c | 22 ++++++++++++++++++++++
>>> drivers/gpu/drm/amd/amdkfd/kfd_priv.h | 1 +
>>> 5 files changed, 52 insertions(+)
>>>
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
>>> index 7b10bbe28caf..d1dac3412a66 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
>>> @@ -36,6 +36,7 @@
>>> #include "amdgpu_ras.h"
>>> #include "amdgpu_umc.h"
>>> #include "amdgpu_reset.h"
>>> +#include "kfd_priv.h"
>>> /* Total memory size in system memory and all GPU VRAM. Used to
>>> * estimate worst case amount of memory to reserve for page tables
>>> @@ -320,6 +321,27 @@ void amdgpu_amdkfd_gpu_reset(struct amdgpu_device
>>> *adev)
>>> (void)amdgpu_reset_domain_schedule(adev->reset_domain,
>>> &adev->kfd.reset_work);
>>> }
>>> +void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev)
>>> +{
>>> + struct kfd_dev *kfd = adev->kfd.dev;
>>> + unsigned int i;
>>> +
>>> + if (!kfd)
>>> + return;
>>> +
>>> + for (i = 0; i < kfd->num_nodes; i++) {
>>> + struct kfd_node *node = kfd->nodes[i];
>>> +
>>> + kfd_dev_unmap_mapping_range(KFD_MMAP_TYPE_DOORBELL |
>>> + KFD_MMAP_GPU_ID(node->id),
>>> + kfd_doorbell_process_slice(kfd));
>>> + kfd_dev_unmap_mapping_range(KFD_MMAP_TYPE_MMIO |
>>> + KFD_MMAP_GPU_ID(node->id),
>>> + PAGE_SIZE);
>>> + }
>>> +}
>>> +
>>> +
>>> int amdgpu_amdkfd_alloc_kernel_mem(struct amdgpu_device *adev, size_t
>>> size,
>>> u32 domain, void **mem_obj, uint64_t *gpu_addr,
>>> void **cpu_ptr, bool cp_mqd_gfx9)
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
>>> index 2bf6a31c194d..5333e052d56d 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
>>> @@ -360,6 +360,7 @@ int amdgpu_amdkfd_reserve_mem_limit(struct
>>> amdgpu_device *adev,
>>> uint64_t size, u32 alloc_flag, int8_t xcp_id);
>>> void amdgpu_amdkfd_unreserve_mem_limit(struct amdgpu_device *adev,
>>> uint64_t size, u32 alloc_flag, int8_t xcp_id);
>>> +void amdgpu_amdkfd_clear_kfd_mapping(struct amdgpu_device *adev);
>>> u64 amdgpu_amdkfd_xcp_memory_size(struct amdgpu_device *adev, int
>>> xcp_id);
>>> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> index 1202a72ff063..6760c9331f46 100644
>>> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_device.c
>>> @@ -5844,6 +5844,12 @@ int amdgpu_device_gpu_recover(struct amdgpu_device
>>> *adev,
>>> /* We need to lock reset domain only once both for XGMI and single
>>> device */
>>> amdgpu_device_recovery_get_reset_lock(adev, &device_list);
>>> + /* unmap all the mappings of doorbell and framebuffer to prevent
>>> user space from
>>> + * accessing them
>>> + */
>>> + unmap_mapping_range(adev->ddev.anon_inode->i_mapping, 0, 0, 1);
>>> + amdgpu_amdkfd_clear_kfd_mapping(adev);
>>> +
>>> amdgpu_device_halt_activities(adev, job, reset_context, &device_list,
>>> hive, need_emergency_restart);
>>> if (need_emergency_restart)
>>> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>>> b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>>> index 84b9bde7f371..1be1b1dd2341 100644
>>> --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>>> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
>>> @@ -69,6 +69,21 @@ static const struct class kfd_class = {
>>> .name = kfd_dev_name,
>>> };
>>> +/*
>>> + * 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().
>>> + */
>>> +static struct address_space *kfd_dev_mapping;
>>> +
>>> +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);
>>> +}
>>> +
>>> static inline struct kfd_process_device *kfd_lock_pdd_by_id(struct
>>> kfd_process *p, __u32 gpu_id)
>>> {
>>> struct kfd_process_device *pdd;
>>> @@ -135,6 +150,13 @@ 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);
>> That stuff looks really odd. Mostly @Felix why is that necessary?
>>
>> Apart from that the patch looks good to me.
>
> My understanding is, that kfd_dev_mapping caches the mapping in a global
> variable, which is OK because there is only one KFD device node. Using
> cmpxchg is a reliable way to update it without holding a lock the first time
> kfd_open is called.
>
> It's not pretty, but I can't think of a better way of doing this.
Well you somewhere allocates the device node and that should have an inode
field which in turn has an i_mapping field which contains that value.
I don't know the kfd code well enough to judge where that is but in theory it
should be much simpler.
Regards,
Christian.
>
> Regards,
> Felix
>
>
>>
>> Regards,
>> Christian.
>>
>>
>>> +
>>> is_32bit_user_mode = in_compat_syscall();
>>> if (is_32bit_user_mode) {
>>> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
>>> b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
>>> index a6ff1db477f9..f037062c33ea 100644
>>> --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
>>> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
>>> @@ -399,6 +399,7 @@ enum kfd_mempool {
>>> /* Character device interface */
>>> int kfd_chardev_init(void);
>>> void kfd_chardev_exit(void);
>>> +void kfd_dev_unmap_mapping_range(loff_t const holebegin, loff_t const
>>> holelen);
>>> /**
>>> * enum kfd_unmap_queues_filter - Enum for queue filters.