mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2026-08-09 06:14:34 +02:00
CCS read/write buffers are freed during BO destruction. In some cases,
BOs may be destroyed after the device is unbound but while the DRM
structure remains valid, leading to NULL pointer dereferences when
accessing device resources.
BUG: kernel NULL pointer dereference, address: 0000000000000000
PGD 0 P4D 0
Oops: Oops: 0000 [#1] SMP NOPTI
CPU: 0 UID: 0 PID: 9376 Comm: xe_pat Not tainted 7.2.0-rc2+ #1 PREEMPT(lazy)
RIP: 0010:xe_sriov_vf_ccs_rw_update_bb_addr+0x4d/0xa0 [xe]
RSP: 0018:ffffcf304110b9c8 EFLAGS: 00010246
RAX: ffff8a85c38a0a00 RBX: 00000000810ef000 RCX: 0000000000000000
RDX: 0000000000000000 RSI: 0000000000000000 RDI: ffff8a85c39c1888
RBP: ffffcf304110b9e8 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000000 R12: ffff8a85c39c1888
R13: 0000000000000000 R14: ffff8a85c39b4f28 R15: ffff8a85c3885000
FS: 0000000000000000(0000) GS:ffff8a878b809000(0000) knlGS:0000000000000000
CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033
CR2: 0000000000000000 CR3: 000000010314a002 CR4: 0000000000772ef0
PKRU: 55555554
Call Trace:
<TASK>
xe_migrate_ccs_rw_copy_clear+0x98/0x120 [xe]
xe_sriov_vf_ccs_detach_bo+0x2c/0x60 [xe]
xe_ttm_bo_delete_mem_notify+0xc8/0xe0 [xe]
ttm_bo_cleanup_memtype_use+0x26/0x80 [ttm]
ttm_bo_release+0x29e/0x2d0 [ttm]
ttm_bo_fini+0x39/0x70 [ttm]
xe_gem_object_free+0x1f/0x30 [xe]
drm_gem_object_free+0x1d/0x40
ttm_bo_vm_close+0x5f/0x90 [ttm]
remove_vma+0x2c/0x70
tear_down_vmas+0x63/0xf0
exit_mmap+0x20d/0x3f0
__mmput+0x45/0x170
mmput+0x31/0x40
do_exit+0x2ba/0xac0
do_group_exit+0x2d/0xb0
__x64_sys_exit_group+0x18/0x20
x64_sys_call+0x14a0/0x2390
do_syscall_64+0xdd/0x640
? count_memcg_events+0xea/0x240
? handle_mm_fault+0x1ec/0x2f0
Fixes: 864690cf4d ("drm/xe/vf: Attach and detach CCS copy commands with BO")
Signed-off-by: Satyanarayana K V P <satyanarayana.k.v.p@intel.com>
Cc: Matthew Brost <matthew.brost@intel.com>
Cc: Michal Wajdeczko <michal.wajdeczko@intel.com>
Reviewed-by: Matthew Brost <matthew.brost@intel.com>
Signed-off-by: Matthew Brost <matthew.brost@intel.com>
Link: https://patch.msgid.link/20260721052215.2267228-2-satyanarayana.k.v.p@intel.com
(cherry picked from commit 1ae415a6eefe5004954a1d352b1718faca8844ef)
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
186 lines
5.7 KiB
C
186 lines
5.7 KiB
C
/* SPDX-License-Identifier: MIT */
|
|
/*
|
|
* Copyright © 2020 Intel Corporation
|
|
*/
|
|
|
|
#ifndef _XE_MIGRATE_H_
|
|
#define _XE_MIGRATE_H_
|
|
|
|
#include <linux/types.h>
|
|
|
|
struct dma_fence;
|
|
struct drm_pagemap_addr;
|
|
struct iosys_map;
|
|
struct ttm_resource;
|
|
|
|
struct xe_bo;
|
|
struct xe_gt;
|
|
struct xe_tlb_inval_job;
|
|
struct xe_exec_queue;
|
|
struct xe_migrate;
|
|
struct xe_migrate_pt_update;
|
|
struct xe_sync_entry;
|
|
struct xe_pt;
|
|
struct xe_tile;
|
|
struct xe_vm;
|
|
struct xe_vm_pgtable_update;
|
|
struct xe_vma;
|
|
|
|
enum xe_sriov_vf_ccs_rw_ctxs;
|
|
|
|
enum xe_migrate_copy_dir {
|
|
XE_MIGRATE_COPY_TO_VRAM,
|
|
XE_MIGRATE_COPY_TO_SRAM,
|
|
};
|
|
|
|
/**
|
|
* struct xe_migrate_pt_update_ops - Callbacks for the
|
|
* xe_migrate_update_pgtables() function.
|
|
*/
|
|
struct xe_migrate_pt_update_ops {
|
|
/**
|
|
* @populate: Populate a command buffer or page-table with ptes.
|
|
* @pt_update: Embeddable callback argument.
|
|
* @tile: The tile for the current operation.
|
|
* @map: struct iosys_map into the memory to be populated.
|
|
* @pos: If @map is NULL, map into the memory to be populated.
|
|
* @ofs: qword offset into @map, unused if @map is NULL.
|
|
* @num_qwords: Number of qwords to write.
|
|
* @update: Information about the PTEs to be inserted.
|
|
*
|
|
* This interface is intended to be used as a callback into the
|
|
* page-table system to populate command buffers or shared
|
|
* page-tables with PTEs.
|
|
*/
|
|
void (*populate)(struct xe_migrate_pt_update *pt_update,
|
|
struct xe_tile *tile, struct iosys_map *map,
|
|
void *pos, u32 ofs, u32 num_qwords,
|
|
const struct xe_vm_pgtable_update *update);
|
|
/**
|
|
* @clear: Clear a command buffer or page-table with ptes.
|
|
* @pt_update: Embeddable callback argument.
|
|
* @tile: The tile for the current operation.
|
|
* @map: struct iosys_map into the memory to be populated.
|
|
* @pos: If @map is NULL, map into the memory to be populated.
|
|
* @ofs: qword offset into @map, unused if @map is NULL.
|
|
* @num_qwords: Number of qwords to write.
|
|
* @update: Information about the PTEs to be inserted.
|
|
*
|
|
* This interface is intended to be used as a callback into the
|
|
* page-table system to populate command buffers or shared
|
|
* page-tables with PTEs.
|
|
*/
|
|
void (*clear)(struct xe_migrate_pt_update *pt_update,
|
|
struct xe_tile *tile, struct iosys_map *map,
|
|
void *pos, u32 ofs, u32 num_qwords,
|
|
const struct xe_vm_pgtable_update *update);
|
|
|
|
/**
|
|
* @pre_commit: Callback to be called just before arming the
|
|
* sched_job.
|
|
* @pt_update: Pointer to embeddable callback argument.
|
|
*
|
|
* Return: 0 on success, negative error code on error.
|
|
*/
|
|
int (*pre_commit)(struct xe_migrate_pt_update *pt_update);
|
|
};
|
|
|
|
/**
|
|
* struct xe_migrate_pt_update - Argument to the
|
|
* struct xe_migrate_pt_update_ops callbacks.
|
|
*
|
|
* Intended to be subclassed to support additional arguments if necessary.
|
|
*/
|
|
struct xe_migrate_pt_update {
|
|
/** @ops: Pointer to the struct xe_migrate_pt_update_ops callbacks */
|
|
const struct xe_migrate_pt_update_ops *ops;
|
|
/** @vops: VMA operations */
|
|
struct xe_vma_ops *vops;
|
|
/** @job: The job if a GPU page-table update. NULL otherwise */
|
|
struct xe_sched_job *job;
|
|
/**
|
|
* @ijob: The TLB invalidation job for primary GT. NULL otherwise
|
|
*/
|
|
struct xe_tlb_inval_job *ijob;
|
|
/**
|
|
* @mjob: The TLB invalidation job for media GT. NULL otherwise
|
|
*/
|
|
struct xe_tlb_inval_job *mjob;
|
|
/** @tile_id: Tile ID of the update */
|
|
u8 tile_id;
|
|
};
|
|
|
|
struct xe_migrate *xe_migrate_alloc(struct xe_tile *tile);
|
|
int xe_migrate_init(struct xe_migrate *m);
|
|
|
|
struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m,
|
|
unsigned long npages,
|
|
struct drm_pagemap_addr *src_addr,
|
|
u64 dst_addr,
|
|
struct dma_fence *deps);
|
|
|
|
struct dma_fence *xe_migrate_from_vram(struct xe_migrate *m,
|
|
unsigned long npages,
|
|
u64 src_addr,
|
|
struct drm_pagemap_addr *dst_addr,
|
|
struct dma_fence *deps);
|
|
|
|
struct dma_fence *xe_migrate_copy(struct xe_migrate *m,
|
|
struct xe_bo *src_bo,
|
|
struct xe_bo *dst_bo,
|
|
struct ttm_resource *src,
|
|
struct ttm_resource *dst,
|
|
bool copy_only_ccs);
|
|
|
|
struct dma_fence *xe_migrate_resolve(struct xe_migrate *m,
|
|
struct xe_bo *bo,
|
|
struct ttm_resource *res);
|
|
|
|
int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q,
|
|
struct xe_bo *src_bo,
|
|
struct ttm_resource *new_mem,
|
|
enum xe_sriov_vf_ccs_rw_ctxs read_write);
|
|
|
|
void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo,
|
|
enum xe_sriov_vf_ccs_rw_ctxs read_write,
|
|
bool bound);
|
|
|
|
struct xe_lrc *xe_migrate_lrc(struct xe_migrate *migrate);
|
|
struct xe_exec_queue *xe_migrate_exec_queue(struct xe_migrate *migrate);
|
|
struct dma_fence *xe_migrate_vram_copy_chunk(struct xe_bo *vram_bo, u64 vram_offset,
|
|
struct xe_bo *sysmem_bo, u64 sysmem_offset,
|
|
u64 size, enum xe_migrate_copy_dir dir);
|
|
int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo,
|
|
unsigned long offset, void *buf, int len,
|
|
int write);
|
|
|
|
#define XE_MIGRATE_CLEAR_FLAG_BO_DATA BIT(0)
|
|
#define XE_MIGRATE_CLEAR_FLAG_CCS_DATA BIT(1)
|
|
#define XE_MIGRATE_CLEAR_FLAG_FULL (XE_MIGRATE_CLEAR_FLAG_BO_DATA | \
|
|
XE_MIGRATE_CLEAR_FLAG_CCS_DATA)
|
|
struct dma_fence *xe_migrate_clear(struct xe_migrate *m,
|
|
struct xe_bo *bo,
|
|
struct ttm_resource *dst,
|
|
u32 clear_flags);
|
|
|
|
struct xe_vm *xe_migrate_get_vm(struct xe_migrate *m);
|
|
|
|
struct dma_fence *
|
|
xe_migrate_update_pgtables(struct xe_migrate *m,
|
|
struct xe_migrate_pt_update *pt_update);
|
|
|
|
void xe_migrate_wait(struct xe_migrate *m);
|
|
|
|
#if IS_ENABLED(CONFIG_PROVE_LOCKING)
|
|
void xe_migrate_job_lock_assert(struct xe_exec_queue *q);
|
|
#else
|
|
static inline void xe_migrate_job_lock_assert(struct xe_exec_queue *q)
|
|
{
|
|
}
|
|
#endif
|
|
|
|
void xe_migrate_job_lock(struct xe_migrate *m, struct xe_exec_queue *q);
|
|
void xe_migrate_job_unlock(struct xe_migrate *m, struct xe_exec_queue *q);
|
|
|
|
#endif
|