Driver Changes:

- Fix BO prefetch with CONSULT_MEM_ADVISE_PREF_LOCK (Himal)
 - Hold a dma-buf reference for imported BOs (Nitin)
 - Fix writable override for CRI (Alexander)
 - Fix VF CCS attach/detach race with in-flight BO moves (Matthew Brost)
 - Fix WOPCM size for LNL+ (Daniele)
 - Reset current_op in xe_pt_update_ops_init (Zongyao Bai)
 - Keep scheduler timeline name alive (Arvind)
 - Hold device ref until queue teardown completes (Arvind)
 - Disable display in admin only PF mode (Satyanarayana)
 -----BEGIN PGP SIGNATURE-----
 
 iHQEABYKAB0WIQRskUM7w1oG5rx2IZO4FpNVCsYGvwUCaln1KQAKCRC4FpNVCsYG
 v+t1APjm/aXpCADABLIJbloVUeDaWVJ+v0tfF7HWjr90xqzOAP9QA8QVqgxQ55TN
 5m0wZVcMF1p/T+Rv5r4pGpi7PmLsDg==
 =o4cW
 -----END PGP SIGNATURE-----

Merge tag 'drm-xe-fixes-2026-07-17' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-fixes

Driver Changes:
- Fix BO prefetch with CONSULT_MEM_ADVISE_PREF_LOCK (Himal)
- Hold a dma-buf reference for imported BOs (Nitin)
- Fix writable override for CRI (Alexander)
- Fix VF CCS attach/detach race with in-flight BO moves (Matthew Brost)
- Fix WOPCM size for LNL+ (Daniele)
- Reset current_op in xe_pt_update_ops_init (Zongyao Bai)
- Keep scheduler timeline name alive (Arvind)
- Hold device ref until queue teardown completes (Arvind)
- Disable display in admin only PF mode (Satyanarayana)

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

From: Thomas Hellstrom <thomas.hellstrom@linux.intel.com>
Link: https://patch.msgid.link/aln1tRUXZJ_qzD65@fedora
This commit is contained in:
Dave Airlie 2026-07-18 07:17:28 +10:00
commit e442677c0a
20 changed files with 223 additions and 69 deletions

View File

@ -1102,6 +1102,21 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
xe_pm_runtime_get_noresume(xe);
}
/*
* Attach CCS BBs before submitting the copy job below so a VF
* migration racing the copy sees valid, up to date attach state.
*/
if (IS_VF_CCS_READY(xe) &&
((move_lacks_source && new_mem->mem_type == XE_PL_TT) ||
(old_mem_type == XE_PL_SYSTEM && new_mem->mem_type == XE_PL_TT)) &&
handle_system_ccs) {
ret = xe_sriov_vf_ccs_attach_bo(bo, new_mem);
if (ret) {
xe_pm_runtime_put(xe);
goto out;
}
}
if (move_lacks_source) {
u32 flags = 0;
@ -1139,22 +1154,19 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict,
ttm_bo_move_null(ttm_bo, new_mem);
}
dma_fence_put(fence);
xe_pm_runtime_put(xe);
/*
* CCS meta data is migrated from TT -> SMEM. So, let us detach the
* BBs from BO as it is no longer needed.
* Detach must wait for the copy above to complete: a VF migration
* racing an in-flight copy must still see valid CCS BBs, so don't
* tear them down until the copy fence has signaled.
*/
if (IS_VF_CCS_READY(xe) && old_mem_type == XE_PL_TT &&
new_mem->mem_type == XE_PL_SYSTEM)
new_mem->mem_type == XE_PL_SYSTEM) {
dma_fence_wait(fence, false);
xe_sriov_vf_ccs_detach_bo(bo);
}
if (IS_VF_CCS_READY(xe) &&
((move_lacks_source && new_mem->mem_type == XE_PL_TT) ||
(old_mem_type == XE_PL_SYSTEM && new_mem->mem_type == XE_PL_TT)) &&
handle_system_ccs)
ret = xe_sriov_vf_ccs_attach_bo(bo);
dma_fence_put(fence);
xe_pm_runtime_put(xe);
out:
if ((!ttm_bo->resource || ttm_bo->resource->mem_type == XE_PL_SYSTEM) &&
@ -1349,7 +1361,7 @@ int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
backup = xe_bo_init_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, xe_bo_size(bo),
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
XE_BO_FLAG_PINNED, &exec);
XE_BO_FLAG_PINNED, NULL, &exec);
if (IS_ERR(backup)) {
drm_exec_retry_on_contention(&exec);
ret = PTR_ERR(backup);
@ -1490,7 +1502,7 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
xe_bo_size(bo),
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
XE_BO_FLAG_PINNED, &exec);
XE_BO_FLAG_PINNED, NULL, &exec);
if (IS_ERR(backup)) {
drm_exec_retry_on_contention(&exec);
ret = PTR_ERR(backup);
@ -1826,6 +1838,8 @@ static void xe_ttm_bo_destroy(struct ttm_buffer_object *ttm_bo)
if (bo->ttm.base.import_attach)
drm_prime_gem_destroy(&bo->ttm.base, NULL);
if (bo->dma_buf)
dma_buf_put(bo->dma_buf);
drm_gem_object_release(&bo->ttm.base);
xe_assert(xe, list_empty(&ttm_bo->base.gpuva.list));
@ -2283,6 +2297,8 @@ void xe_bo_free(struct xe_bo *bo)
* @cpu_caching: The cpu caching used for system memory backing store.
* @type: The TTM buffer object type.
* @flags: XE_BO_FLAG_ flags.
* @dma_buf: The dma-buf to reference for the BO lifetime (imported BOs),
* or NULL.
* @exec: The drm_exec transaction to use for exhaustive eviction.
*
* Initialize or create an xe buffer object. On failure, any allocated buffer
@ -2294,7 +2310,8 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
struct xe_tile *tile, struct dma_resv *resv,
struct ttm_lru_bulk_move *bulk, size_t size,
u16 cpu_caching, enum ttm_bo_type type,
u32 flags, struct drm_exec *exec)
u32 flags, struct dma_buf *dma_buf,
struct drm_exec *exec)
{
struct ttm_operation_ctx ctx = {
.interruptible = true,
@ -2383,6 +2400,17 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
placement = (type == ttm_bo_type_sg ||
bo->flags & XE_BO_FLAG_DEFER_BACKING) ? &sys_placement :
&bo->placement;
/*
* For imported BOs, keep the exporter dma-buf alive for the BO
* lifetime. Taken before ttm_bo_init_reserved() to also cover a
* creation failure there. Released in xe_ttm_bo_destroy().
*/
if (dma_buf) {
get_dma_buf(dma_buf);
bo->dma_buf = dma_buf;
}
err = ttm_bo_init_reserved(&xe->ttm, &bo->ttm, type,
placement, alignment,
&ctx, NULL, resv, xe_ttm_bo_destroy);
@ -2500,7 +2528,7 @@ __xe_bo_create_locked(struct xe_device *xe,
vm && !xe_vm_in_fault_mode(vm) &&
flags & XE_BO_FLAG_USER ?
&vm->lru_bulk_move : NULL, size,
cpu_caching, type, flags, exec);
cpu_caching, type, flags, NULL, exec);
if (IS_ERR(bo))
return bo;

View File

@ -118,7 +118,8 @@ struct xe_bo *xe_bo_init_locked(struct xe_device *xe, struct xe_bo *bo,
struct xe_tile *tile, struct dma_resv *resv,
struct ttm_lru_bulk_move *bulk, size_t size,
u16 cpu_caching, enum ttm_bo_type type,
u32 flags, struct drm_exec *exec);
u32 flags, struct dma_buf *dma_buf,
struct drm_exec *exec);
struct xe_bo *xe_bo_create_locked(struct xe_device *xe, struct xe_tile *tile,
struct xe_vm *vm, size_t size,
enum ttm_bo_type type, u32 flags,

View File

@ -36,6 +36,8 @@ struct xe_bo {
struct xe_bo *backup_obj;
/** @parent_obj: Ref to parent bo if this a backup_obj */
struct xe_bo *parent_obj;
/** @dma_buf: Imported dma-buf ref to keep its resv alive. */
struct dma_buf *dma_buf;
/** @flags: flags for this buffer object */
u32 flags;
/** @vm: VM this BO is attached to, for extobj this will be NULL */

View File

@ -426,7 +426,6 @@ static const struct drm_ioctl_desc xe_ioctls_admin_only[] = {
static const struct drm_driver admin_only_driver = {
.driver_features =
XE_DISPLAY_DRIVER_FEATURES |
DRIVER_GEM | DRIVER_RENDER | DRIVER_GEM_GPUVA,
.open = xe_file_open,
.postclose = xe_file_close,
@ -438,7 +437,6 @@ static const struct drm_driver admin_only_driver = {
.major = DRIVER_MAJOR,
.minor = DRIVER_MINOR,
.patchlevel = DRIVER_PATCHLEVEL,
XE_DISPLAY_DRIVER_OPS,
};
/**
@ -580,7 +578,7 @@ int xe_device_init_early(struct xe_device *xe)
WQ_MEM_RECLAIM);
xe->ordered_wq = alloc_ordered_workqueue("xe-ordered-wq", 0);
xe->unordered_wq = alloc_workqueue("xe-unordered-wq", WQ_PERCPU, 0);
xe->destroy_wq = alloc_workqueue("xe-destroy-wq", WQ_PERCPU, 0);
xe->destroy_wq = alloc_workqueue("xe-destroy-wq", WQ_PERCPU | WQ_MEM_RECLAIM, 0);
if (!xe->ordered_wq || !xe->unordered_wq ||
!xe->preempt_fence_wq || !xe->destroy_wq) {
/*

View File

@ -355,7 +355,7 @@ struct xe_device {
/** @unordered_wq: used to serialize unordered work */
struct workqueue_struct *unordered_wq;
/** @destroy_wq: used to serialize user destroy work, like queue */
/** @destroy_wq: used to serialize SVM pagemap destroy work */
struct workqueue_struct *destroy_wq;
/** @tiles: device tiles */

View File

@ -302,7 +302,7 @@ xe_dma_buf_create_obj(struct drm_device *dev, struct dma_buf *dma_buf)
bo = xe_bo_init_locked(xe, NULL, NULL, resv, NULL, dma_buf->size,
0, /* Will require 1way or 2way for vm_bind */
ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, &exec);
ttm_bo_type_sg, XE_BO_FLAG_SYSTEM, dma_buf, &exec);
drm_exec_retry_on_contention(&exec);
if (IS_ERR(bo)) {
ret = PTR_ERR(bo);

View File

@ -10,6 +10,7 @@
#include <linux/workqueue.h>
#include "xe_gpu_scheduler_types.h"
#include "xe_hw_fence_types.h"
struct dma_fence;
struct xe_exec_queue;
@ -24,6 +25,10 @@ struct xe_guc_exec_queue {
struct rcu_head rcu;
/** @sched: GPU scheduler for this xe_exec_queue */
struct xe_gpu_scheduler sched;
/**
* @name: Scheduler timeline name, kept with @sched until RCU free.
*/
char name[MAX_FENCE_NAME_LEN];
/** @entity: Scheduler entity for this xe_exec_queue */
struct xe_sched_entity entity;
/**

View File

@ -10,6 +10,7 @@
#include <linux/circ_buf.h>
#include <linux/dma-fence-array.h>
#include <drm/drm_drv.h>
#include <drm/drm_managed.h>
#include "abi/guc_actions_abi.h"
@ -37,6 +38,7 @@
#include "xe_macros.h"
#include "xe_map.h"
#include "xe_mocs.h"
#include "xe_module.h"
#include "xe_pm.h"
#include "xe_ring_ops_types.h"
#include "xe_sched_job.h"
@ -232,17 +234,9 @@ static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q)
static void guc_submit_sw_fini(struct drm_device *drm, void *arg)
{
struct xe_guc *guc = arg;
struct xe_device *xe = guc_to_xe(guc);
struct xe_gt *gt = guc_to_gt(guc);
int ret;
ret = wait_event_timeout(guc->submission_state.fini_wq,
xa_empty(&guc->submission_state.exec_queue_lookup),
HZ * 5);
drain_workqueue(xe->destroy_wq);
xe_gt_assert(gt, ret);
xe_gt_assert(gt, xa_empty(&guc->submission_state.exec_queue_lookup));
xa_destroy(&guc->submission_state.exec_queue_lookup);
}
@ -319,8 +313,6 @@ int xe_guc_submit_init(struct xe_guc *guc, unsigned int num_ids)
xa_init(&guc->submission_state.exec_queue_lookup);
init_waitqueue_head(&guc->submission_state.fini_wq);
primelockdep(guc);
guc->submission_state.initialized = true;
@ -411,9 +403,6 @@ static void __release_guc_id(struct xe_guc *guc, struct xe_exec_queue *q,
xe_guc_id_mgr_release_locked(&guc->submission_state.idm,
q->guc->id, q->width);
if (xa_empty(&guc->submission_state.exec_queue_lookup))
wake_up(&guc->submission_state.fini_wq);
mutex_unlock(&guc->submission_state.lock);
}
@ -1685,6 +1674,7 @@ static void guc_exec_queue_fini(struct xe_exec_queue *q)
{
struct xe_guc_exec_queue *ge = q->guc;
struct xe_guc *guc = exec_queue_to_guc(q);
struct drm_device *drm = &guc_to_xe(guc)->drm;
if (xe_exec_queue_is_multi_queue_secondary(q)) {
struct xe_exec_queue_group *group = q->multi_queue.group;
@ -1703,36 +1693,52 @@ static void guc_exec_queue_fini(struct xe_exec_queue *q)
* (timeline name).
*/
kfree_rcu(ge, rcu);
drm_dev_put(drm);
}
static void guc_exec_queue_do_destroy(struct xe_exec_queue *q)
{
struct xe_guc_exec_queue *ge = q->guc;
struct xe_guc *guc = exec_queue_to_guc(q);
struct xe_device *xe = guc_to_xe(guc);
struct drm_device *drm = &xe->drm;
/*
* guc_exec_queue_fini() drops the queue's drm_device ref.
* Keep the device alive until the PM-runtime guard unwinds.
*/
drm_dev_get(drm);
scoped_guard(xe_pm_runtime, xe) {
trace_xe_exec_queue_destroy(q);
/* Confirm no work left behind accessing device structures */
cancel_delayed_work_sync(&ge->sched.base.work_tdr);
xe_exec_queue_fini(q);
}
drm_dev_put(drm);
}
static void __guc_exec_queue_destroy_async(struct work_struct *w)
{
struct xe_guc_exec_queue *ge =
container_of(w, struct xe_guc_exec_queue, destroy_async);
struct xe_exec_queue *q = ge->q;
struct xe_guc *guc = exec_queue_to_guc(q);
guard(xe_pm_runtime)(guc_to_xe(guc));
trace_xe_exec_queue_destroy(q);
/* Confirm no work left behind accessing device structures */
cancel_delayed_work_sync(&ge->sched.base.work_tdr);
xe_exec_queue_fini(q);
guc_exec_queue_do_destroy(ge->q);
}
static void guc_exec_queue_destroy_async(struct xe_exec_queue *q)
{
struct xe_guc *guc = exec_queue_to_guc(q);
struct xe_device *xe = guc_to_xe(guc);
INIT_WORK(&q->guc->destroy_async, __guc_exec_queue_destroy_async);
/* We must block on kernel engines so slabs are empty on driver unload */
if (q->flags & EXEC_QUEUE_FLAG_PERMANENT || exec_queue_wedged(q))
__guc_exec_queue_destroy_async(&q->guc->destroy_async);
guc_exec_queue_do_destroy(q);
else
queue_work(xe->destroy_wq, &q->guc->destroy_async);
xe_destroy_wq_queue(&q->guc->destroy_async);
}
static void __guc_exec_queue_destroy(struct xe_guc *guc, struct xe_exec_queue *q)
@ -1927,6 +1933,7 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
{
struct xe_gpu_scheduler *sched;
struct xe_guc *guc = exec_queue_to_guc(q);
struct drm_device *drm = &guc_to_xe(guc)->drm;
struct workqueue_struct *submit_wq = NULL;
struct xe_guc_exec_queue *ge;
long timeout;
@ -1938,6 +1945,8 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
if (!ge)
return -ENOMEM;
drm_dev_get(drm);
q->guc = ge;
ge->q = q;
init_rcu_head(&ge->rcu);
@ -1955,6 +1964,8 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
xe_exec_queue_assign_name(q, q->guc->id);
strscpy(ge->name, q->name, sizeof(ge->name));
/*
* Use primary queue's submit_wq for all secondary queues of a
* multi queue group. This serialization avoids any locking around
@ -1969,7 +1980,7 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
err = xe_sched_init(&ge->sched, &drm_sched_ops, &xe_sched_ops,
submit_wq, xe_lrc_ring_size() / MAX_JOB_SIZE_BYTES, 64,
timeout, guc_to_gt(guc)->ordered_wq, NULL,
q->name, gt_to_xe(q->gt)->drm.dev);
ge->name, gt_to_xe(q->gt)->drm.dev);
if (err)
goto err_release_id;
@ -2014,6 +2025,7 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
release_guc_id(guc, q);
err_free:
kfree(ge);
drm_dev_put(drm);
return err;
}

View File

@ -100,8 +100,6 @@ struct xe_guc {
* even initialized - before that not even the lock is valid
*/
bool initialized;
/** @submission_state.fini_wq: submit fini wait queue */
wait_queue_head_t fini_wq;
} submission_state;
/** @hwconfig: Hardware config state */

View File

@ -1166,6 +1166,8 @@ static int emit_flush_invalidate(u32 *dw, int i, u32 flags)
* @tile: Tile whose migration context to be used.
* @q : Execution to be used along with migration context.
* @src_bo: The buffer object @src is currently bound to.
* @new_mem: The (not yet committed) destination resource @src_bo is being
* moved into; src_bo->ttm.resource is still the old resource.
* @read_write : Creates BB commands for CCS read/write.
*
* Creates batch buffer instructions to copy CCS metadata from CCS pool to
@ -1177,12 +1179,13 @@ static int emit_flush_invalidate(u32 *dw, int i, u32 flags)
*/
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)
{
bool src_is_pltt = read_write == XE_SRIOV_VF_CCS_READ_CTX;
bool dst_is_pltt = read_write == XE_SRIOV_VF_CCS_WRITE_CTX;
struct ttm_resource *src = src_bo->ttm.resource;
struct ttm_resource *src = new_mem;
struct xe_migrate *m = tile->migrate;
struct xe_gt *gt = tile->primary_gt;
u32 batch_size, batch_size_allocated;

View File

@ -138,6 +138,7 @@ struct dma_fence *xe_migrate_resolve(struct xe_migrate *m,
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,

View File

@ -7,6 +7,7 @@
#include <linux/init.h>
#include <linux/module.h>
#include <linux/workqueue.h>
#include <drm/drm_module.h>
@ -91,6 +92,50 @@ static int xe_check_nomodeset(void)
return 0;
}
static struct workqueue_struct *xe_destroy_wq;
static int __init xe_destroy_wq_module_init(void)
{
xe_destroy_wq = alloc_workqueue("xe-guc-destroy-wq", WQ_UNBOUND, 0);
if (!xe_destroy_wq)
return -ENOMEM;
return 0;
}
static void xe_destroy_wq_module_exit(void)
{
if (xe_destroy_wq)
destroy_workqueue(xe_destroy_wq);
xe_destroy_wq = NULL;
}
/**
* xe_destroy_wq_queue() - Queue work on the destroy workqueue
* @work: work item to queue
*
* The destroy workqueue has module lifetime and is used for GuC exec queue
* teardown that can outlive a single xe_device. SVM pagemap destroy uses the
* per-device xe->destroy_wq instead.
*
* Return: %true if @work was queued, %false if it was already pending.
*/
bool xe_destroy_wq_queue(struct work_struct *work)
{
return queue_work(xe_destroy_wq, work);
}
/**
* xe_destroy_wq_flush() - Flush the destroy workqueue
*
* Drains all pending destroy work. Called from PCI remove to ensure
* teardown ordering before the device is destroyed.
*/
void xe_destroy_wq_flush(void)
{
if (xe_destroy_wq)
flush_workqueue(xe_destroy_wq);
}
struct init_funcs {
int (*init)(void);
void (*exit)(void);
@ -112,6 +157,10 @@ static const struct init_funcs init_funcs[] = {
.init = xe_sched_job_module_init,
.exit = xe_sched_job_module_exit,
},
{
.init = xe_destroy_wq_module_init,
.exit = xe_destroy_wq_module_exit,
},
{
.init = xe_register_pci_driver,
.exit = xe_unregister_pci_driver,

View File

@ -8,6 +8,8 @@
#include <linux/types.h>
struct work_struct;
/* Module modprobe variables */
struct xe_modparam {
bool force_execlist;
@ -27,5 +29,8 @@ struct xe_modparam {
extern struct xe_modparam xe_modparam;
bool xe_destroy_wq_queue(struct work_struct *work);
void xe_destroy_wq_flush(void);
#endif

View File

@ -60,35 +60,40 @@ static bool xe_nvm_writable_override(struct xe_device *xe)
struct xe_mmio *mmio = xe_root_tile_mmio(xe);
bool writable_override;
struct xe_reg reg;
u32 test_bit;
u32 test_bit, test_val;
switch (xe->info.platform) {
case XE_CRESCENTISLAND:
reg = PCODE_SCRATCH(0);
test_bit = FDO_MODE;
test_val = FDO_MODE;
break;
case XE_BATTLEMAGE:
reg = HECI_FWSTS2(DG2_GSC_HECI2_BASE);
test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE;
test_val = 0;
break;
case XE_PVC:
reg = HECI_FWSTS2(PVC_GSC_HECI2_BASE);
test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE;
test_val = 0;
break;
case XE_DG2:
reg = HECI_FWSTS2(DG2_GSC_HECI2_BASE);
test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE;
test_val = 0;
break;
case XE_DG1:
reg = HECI_FWSTS2(DG1_GSC_HECI2_BASE);
test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE;
test_val = 0;
break;
default:
drm_err(&xe->drm, "Unknown platform\n");
return true;
}
writable_override = !(xe_mmio_read32(mmio, reg) & test_bit);
writable_override = (xe_mmio_read32(mmio, reg) & test_bit) == test_val;
if (writable_override)
drm_info(&xe->drm, "NVM access overridden by jumper\n");
return writable_override;

View File

@ -788,7 +788,8 @@ static int xe_info_init_early(struct xe_device *xe,
xe->info.probe_display = IS_ENABLED(CONFIG_DRM_XE_DISPLAY) &&
xe_modparam.probe_display &&
desc->has_display;
desc->has_display &&
!xe_device_is_admin_only(xe);
xe->info.force_execlist = xe_modparam.force_execlist;
xe_assert(xe, desc->max_gt_per_tile > 0);
@ -1048,6 +1049,12 @@ static void xe_pci_remove(struct pci_dev *pdev)
return;
xe_device_remove(xe);
/*
* Preserve remove-time flush after moving destroy work to module
* lifetime.
*/
xe_destroy_wq_flush();
xe_pm_fini(xe);
}

View File

@ -2365,8 +2365,11 @@ static void
xe_pt_update_ops_init(struct xe_vm_pgtable_update_ops *pt_update_ops)
{
init_llist_head(&pt_update_ops->deferred);
pt_update_ops->current_op = 0;
pt_update_ops->start = ~0x0ull;
pt_update_ops->last = 0x0ull;
pt_update_ops->needs_svm_lock = false;
pt_update_ops->needs_invalidation = false;
xe_page_reclaim_list_init(&pt_update_ops->prl);
}

View File

@ -404,6 +404,8 @@ void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx)
/**
* xe_sriov_vf_ccs_attach_bo - Insert CCS read write commands in the BO.
* @bo: the &buffer object to which batch buffer commands will be added.
* @new_mem: the (not yet committed) destination resource @bo is being moved
* into; bo->ttm.resource is still the old resource at this point.
*
* This function shall be called only by VF. It inserts the PTEs and copy
* command instructions in the BO by calling xe_migrate_ccs_rw_copy()
@ -411,7 +413,7 @@ void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx)
*
* Returns: 0 if successful, negative error code on failure.
*/
int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo)
int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo, struct ttm_resource *new_mem)
{
struct xe_device *xe = xe_bo_device(bo);
enum xe_sriov_vf_ccs_rw_ctxs ctx_id;
@ -430,7 +432,21 @@ int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo)
xe_assert(xe, !bb);
ctx = &xe->sriov.vf.ccs.contexts[ctx_id];
err = xe_migrate_ccs_rw_copy(tile, ctx->mig_q, bo, ctx_id);
err = xe_migrate_ccs_rw_copy(tile, ctx->mig_q, bo, new_mem, ctx_id);
if (err)
goto err_unwind;
}
return 0;
err_unwind:
/*
* Clean up any contexts already attached. Can't reuse
* xe_sriov_vf_ccs_detach_bo() here as it requires both contexts
* attached before cleaning up either one.
*/
for_each_ccs_rw_ctx(ctx_id) {
if (bo->bb_ccs[ctx_id])
xe_migrate_ccs_rw_copy_clear(bo, ctx_id);
}
return err;
}

View File

@ -11,11 +11,12 @@
#include "xe_sriov_vf_ccs_types.h"
struct drm_printer;
struct ttm_resource;
struct xe_device;
struct xe_bo;
int xe_sriov_vf_ccs_init(struct xe_device *xe);
int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo);
int xe_sriov_vf_ccs_attach_bo(struct xe_bo *bo, struct ttm_resource *new_mem);
int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo);
int xe_sriov_vf_ccs_register_context(struct xe_device *xe);
void xe_sriov_vf_ccs_rebase(struct xe_device *xe);

View File

@ -3255,11 +3255,26 @@ static int op_lock_and_prep(struct drm_exec *exec, struct xe_vm *vm,
.request_decompress = false,
.check_purged = true,
});
if (!err && !xe_vma_has_no_bo(vma))
err = xe_bo_migrate(xe_vma_bo(vma),
region_to_mem_type[region],
NULL,
exec);
if (!err && !xe_vma_has_no_bo(vma)) {
struct xe_bo *bo = xe_vma_bo(vma);
u32 mem_type;
if (region == DRM_XE_CONSULT_MEM_ADVISE_PREF_LOC) {
unsigned int i;
mem_type = XE_PL_TT;
for (i = 0; i < bo->placement.num_placement; i++) {
if (mem_type_is_vram(bo->placements[i].mem_type)) {
mem_type = bo->placements[i].mem_type;
break;
}
}
} else {
mem_type = region_to_mem_type[region];
}
err = xe_bo_migrate(bo, mem_type, NULL, exec);
}
break;
}
default:

View File

@ -49,9 +49,9 @@
*/
/* Default WOPCM size is 2MB from Gen11, 1MB on previous platforms */
/* FIXME: Larger size require for 2 tile PVC, do a proper probe sooner or later */
/* FIXME: Larger size require for some platforms, do a proper probe sooner or later */
#define DGFX_WOPCM_SIZE SZ_4M
/* FIXME: Larger size require for MTL, do a proper probe sooner or later */
#define LNL_WOPCM_SIZE SZ_8M
#define MTL_WOPCM_SIZE SZ_4M
#define WOPCM_SIZE SZ_2M
@ -179,9 +179,14 @@ static int __wopcm_init_regs(struct xe_device *xe, struct xe_gt *gt,
u32 xe_wopcm_size(struct xe_device *xe)
{
return IS_DGFX(xe) ? DGFX_WOPCM_SIZE :
xe->info.platform == XE_METEORLAKE ? MTL_WOPCM_SIZE :
WOPCM_SIZE;
if (xe->info.platform >= XE_LUNARLAKE)
return LNL_WOPCM_SIZE;
else if (IS_DGFX(xe))
return DGFX_WOPCM_SIZE;
else if (xe->info.platform == XE_METEORLAKE)
return MTL_WOPCM_SIZE;
else
return WOPCM_SIZE;
}
static u32 max_wopcm_size(struct xe_device *xe)