mirror of
https://github.com/torvalds/linux.git
synced 2026-07-28 18:21:24 +02:00
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:
commit
e442677c0a
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user