Merge tag 'drm-xe-next-2025-04-28-1' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-next

Core Changes:
- Add drm_coredump_printer_is_full() (Matt Brost)

Driver Changes:
- Do not queue unneeded terminations from debugfs (Daniele)
- Fix out-of-bound while enabling engine activity stats (Michal)
- Use GT oriented message to report engine activity error (Michal)
- Some fault-injection additions (Satyanarayana)
- Fix an error pointer dereference (Harshit)
- Fix capture of steering registers (John)
- Use the steering flag when printing registers (John)
- Cache DSS info when creating capture register list (John)
- Backup VRAM in PM notifier instead of in the suspend / freeze
  callbacks (Matt Auld)
- Fix CFI violation when accessing sysfs files (Jeevaka)
- Fix kernel version docs for temperature and fan speed (Lucas)
- Add devcoredump chunking (Matt Brost)
- Update xe_ttm_access_memory to use GPU for non-visible access
  (Matt Brost)
- Abort printing coredump in VM printer output if full (Matt Brost)
- Resolve a possible circular locking dependency (Harish)
- Don't support EU stall on SRIOV VF (Harish)
- Drop force_alloc from xe_bo_evict in selftests (Matt Brost)

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

From: Thomas Hellstrom <thomas.hellstrom@linux.intel.com>
Link: https://lore.kernel.org/r/aA-mvTb6s909V8hu@fedora
This commit is contained in:
Dave Airlie
2025-04-29 15:54:57 +10:00
32 changed files with 756 additions and 244 deletions

View File

@@ -111,7 +111,7 @@ Description: RO. Package current voltage in millivolt.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp2_input
Date: March 2025
KernelVersion: 6.14
KernelVersion: 6.15
Contact: intel-xe@lists.freedesktop.org
Description: RO. Package temperature in millidegree Celsius.
@@ -119,7 +119,7 @@ Description: RO. Package temperature in millidegree Celsius.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp3_input
Date: March 2025
KernelVersion: 6.14
KernelVersion: 6.15
Contact: intel-xe@lists.freedesktop.org
Description: RO. VRAM temperature in millidegree Celsius.
@@ -127,7 +127,7 @@ Description: RO. VRAM temperature in millidegree Celsius.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan1_input
Date: March 2025
KernelVersion: 6.14
KernelVersion: 6.16
Contact: intel-xe@lists.freedesktop.org
Description: RO. Fan 1 speed in RPM.
@@ -135,7 +135,7 @@ Description: RO. Fan 1 speed in RPM.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan2_input
Date: March 2025
KernelVersion: 6.14
KernelVersion: 6.16
Contact: intel-xe@lists.freedesktop.org
Description: RO. Fan 2 speed in RPM.
@@ -143,7 +143,7 @@ Description: RO. Fan 2 speed in RPM.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan3_input
Date: March 2025
KernelVersion: 6.14
KernelVersion: 6.16
Contact: intel-xe@lists.freedesktop.org
Description: RO. Fan 3 speed in RPM.

View File

@@ -60,7 +60,7 @@ static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
}
/* Evict to system. CCS data should be copied. */
ret = xe_bo_evict(bo, true);
ret = xe_bo_evict(bo);
if (ret) {
KUNIT_FAIL(test, "Failed to evict bo.\n");
return ret;

View File

@@ -65,7 +65,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported,
* the exporter and the importer should be the same bo.
*/
swap(exported->ttm.base.dma_buf, dmabuf);
ret = xe_bo_evict(exported, true);
ret = xe_bo_evict(exported);
swap(exported->ttm.base.dma_buf, dmabuf);
if (ret) {
if (ret != -EINTR && ret != -ERESTARTSYS)

View File

@@ -509,7 +509,7 @@ static void test_migrate(struct xe_device *xe, struct xe_tile *tile,
dma_fence_put(fence);
kunit_info(test, "Evict vram buffer object\n");
ret = xe_bo_evict(vram_bo, true);
ret = xe_bo_evict(vram_bo);
if (ret) {
KUNIT_FAIL(test, "Failed to evict bo.\n");
return;

View File

@@ -1084,6 +1084,80 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
return lret;
}
/**
* xe_bo_notifier_prepare_pinned() - Prepare a pinned VRAM object to be backed
* up in system memory.
* @bo: The buffer object to prepare.
*
* On successful completion, the object backup pages are allocated. Expectation
* is that this is called from the PM notifier, prior to suspend/hibernation.
*
* Return: 0 on success. Negative error code on failure.
*/
int xe_bo_notifier_prepare_pinned(struct xe_bo *bo)
{
struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
struct xe_bo *backup;
int ret = 0;
xe_bo_lock(bo, false);
xe_assert(xe, !bo->backup_obj);
/*
* Since this is called from the PM notifier we might have raced with
* someone unpinning this after we dropped the pinned list lock and
* grabbing the above bo lock.
*/
if (!xe_bo_is_pinned(bo))
goto out_unlock_bo;
if (!xe_bo_is_vram(bo))
goto out_unlock_bo;
if (bo->flags & XE_BO_FLAG_PINNED_NORESTORE)
goto out_unlock_bo;
backup = ___xe_bo_create_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, bo->size,
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
XE_BO_FLAG_PINNED);
if (IS_ERR(backup)) {
ret = PTR_ERR(backup);
goto out_unlock_bo;
}
backup->parent_obj = xe_bo_get(bo); /* Released by bo_destroy */
ttm_bo_pin(&backup->ttm);
bo->backup_obj = backup;
out_unlock_bo:
xe_bo_unlock(bo);
return ret;
}
/**
* xe_bo_notifier_unprepare_pinned() - Undo the previous prepare operation.
* @bo: The buffer object to undo the prepare for.
*
* Always returns 0. The backup object is removed, if still present. Expectation
* it that this called from the PM notifier when undoing the prepare step.
*
* Return: Always returns 0.
*/
int xe_bo_notifier_unprepare_pinned(struct xe_bo *bo)
{
xe_bo_lock(bo, false);
if (bo->backup_obj) {
ttm_bo_unpin(&bo->backup_obj->ttm);
xe_bo_put(bo->backup_obj);
bo->backup_obj = NULL;
}
xe_bo_unlock(bo);
return 0;
}
/**
* xe_bo_evict_pinned() - Evict a pinned VRAM object to system memory
* @bo: The buffer object to move.
@@ -1098,7 +1172,8 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
int xe_bo_evict_pinned(struct xe_bo *bo)
{
struct xe_device *xe = ttm_to_xe_device(bo->ttm.bdev);
struct xe_bo *backup;
struct xe_bo *backup = bo->backup_obj;
bool backup_created = false;
bool unmap = false;
int ret = 0;
@@ -1120,12 +1195,17 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
if (bo->flags & XE_BO_FLAG_PINNED_NORESTORE)
goto out_unlock_bo;
backup = xe_bo_create_locked(xe, NULL, NULL, bo->size, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
XE_BO_FLAG_PINNED);
if (IS_ERR(backup)) {
ret = PTR_ERR(backup);
goto out_unlock_bo;
if (!backup) {
backup = ___xe_bo_create_locked(xe, NULL, NULL, bo->ttm.base.resv, NULL, bo->size,
DRM_XE_GEM_CPU_CACHING_WB, ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS |
XE_BO_FLAG_PINNED);
if (IS_ERR(backup)) {
ret = PTR_ERR(backup);
goto out_unlock_bo;
}
backup->parent_obj = xe_bo_get(bo); /* Released by bo_destroy */
backup_created = true;
}
if (xe_bo_is_user(bo) || (bo->flags & XE_BO_FLAG_PINNED_LATE_RESTORE)) {
@@ -1173,12 +1253,12 @@ int xe_bo_evict_pinned(struct xe_bo *bo)
bo->size);
}
bo->backup_obj = backup;
if (!bo->backup_obj)
bo->backup_obj = backup;
out_backup:
xe_bo_vunmap(backup);
xe_bo_unlock(backup);
if (ret)
if (ret && backup_created)
xe_bo_put(backup);
out_unlock_bo:
if (unmap)
@@ -1212,15 +1292,12 @@ int xe_bo_restore_pinned(struct xe_bo *bo)
if (!backup)
return 0;
xe_bo_lock(backup, false);
xe_bo_lock(bo, false);
ret = ttm_bo_validate(&backup->ttm, &backup->placement, &ctx);
if (ret)
goto out_backup;
if (WARN_ON(!dma_resv_trylock(bo->ttm.base.resv))) {
ret = -EBUSY;
goto out_backup;
if (!xe_bo_is_pinned(backup)) {
ret = ttm_bo_validate(&backup->ttm, &backup->placement, &ctx);
if (ret)
goto out_unlock_bo;
}
if (xe_bo_is_user(bo) || (bo->flags & XE_BO_FLAG_PINNED_LATE_RESTORE)) {
@@ -1261,7 +1338,7 @@ int xe_bo_restore_pinned(struct xe_bo *bo)
if (iosys_map_is_null(&bo->vmap)) {
ret = xe_bo_vmap(bo);
if (ret)
goto out_unlock_bo;
goto out_backup;
unmap = true;
}
@@ -1271,15 +1348,17 @@ int xe_bo_restore_pinned(struct xe_bo *bo)
bo->backup_obj = NULL;
out_backup:
xe_bo_vunmap(backup);
if (!bo->backup_obj) {
if (xe_bo_is_pinned(backup))
ttm_bo_unpin(&backup->ttm);
xe_bo_put(backup);
}
out_unlock_bo:
if (unmap)
xe_bo_vunmap(bo);
xe_bo_unlock(bo);
out_backup:
xe_bo_vunmap(backup);
xe_bo_unlock(backup);
if (!bo->backup_obj)
xe_bo_put(backup);
return ret;
}
@@ -1455,6 +1534,7 @@ static int xe_ttm_access_memory(struct ttm_buffer_object *ttm_bo,
struct xe_res_cursor cursor;
struct xe_vram_region *vram;
int bytes_left = len;
int err = 0;
xe_bo_assert_held(bo);
xe_device_assert_mem_access(xe);
@@ -1462,9 +1542,14 @@ static int xe_ttm_access_memory(struct ttm_buffer_object *ttm_bo,
if (!mem_type_is_vram(ttm_bo->resource->mem_type))
return -EIO;
/* FIXME: Use GPU for non-visible VRAM */
if (!xe_ttm_resource_visible(ttm_bo->resource))
return -EIO;
if (!xe_ttm_resource_visible(ttm_bo->resource) || len >= SZ_16K) {
struct xe_migrate *migrate =
mem_type_to_migrate(xe, ttm_bo->resource->mem_type);
err = xe_migrate_access_memory(migrate, bo, offset, buf, len,
write);
goto out;
}
vram = res_to_mem_region(ttm_bo->resource);
xe_res_first(ttm_bo->resource, offset & PAGE_MASK,
@@ -1488,7 +1573,8 @@ static int xe_ttm_access_memory(struct ttm_buffer_object *ttm_bo,
xe_res_next(&cursor, PAGE_SIZE);
} while (bytes_left);
return len;
out:
return err ?: len;
}
const struct ttm_device_funcs xe_ttm_funcs = {
@@ -1532,6 +1618,9 @@ static void xe_ttm_bo_destroy(struct ttm_buffer_object *ttm_bo)
if (bo->vm && xe_bo_is_user(bo))
xe_vm_put(bo->vm);
if (bo->parent_obj)
xe_bo_put(bo->parent_obj);
mutex_lock(&xe->mem_access.vram_userfault.lock);
if (!list_empty(&bo->vram_userfault_link))
list_del(&bo->vram_userfault_link);
@@ -2306,6 +2395,13 @@ void xe_bo_unpin(struct xe_bo *bo)
xe_assert(xe, !list_empty(&bo->pinned_link));
list_del_init(&bo->pinned_link);
spin_unlock(&xe->pinned.lock);
if (bo->backup_obj) {
if (xe_bo_is_pinned(bo->backup_obj))
ttm_bo_unpin(&bo->backup_obj->ttm);
xe_bo_put(bo->backup_obj);
bo->backup_obj = NULL;
}
}
ttm_bo_unpin(&bo->ttm);
if (bo->ttm.ttm && ttm_tt_is_populated(bo->ttm.ttm))

View File

@@ -277,6 +277,8 @@ int xe_bo_migrate(struct xe_bo *bo, u32 mem_type);
int xe_bo_evict(struct xe_bo *bo);
int xe_bo_evict_pinned(struct xe_bo *bo);
int xe_bo_notifier_prepare_pinned(struct xe_bo *bo);
int xe_bo_notifier_unprepare_pinned(struct xe_bo *bo);
int xe_bo_restore_pinned(struct xe_bo *bo);
int xe_bo_dma_unmap_pinned(struct xe_bo *bo);

View File

@@ -34,7 +34,13 @@ static int xe_bo_apply_to_pinned(struct xe_device *xe,
ret = pinned_fn(bo);
if (ret && pinned_list != new_list) {
spin_lock(&xe->pinned.lock);
list_move(&bo->pinned_link, pinned_list);
/*
* We might no longer be pinned, since PM notifier can
* call this. If the pinned link is now empty, keep it
* that way.
*/
if (!list_empty(&bo->pinned_link))
list_move(&bo->pinned_link, pinned_list);
spin_unlock(&xe->pinned.lock);
}
xe_bo_put(bo);
@@ -47,25 +53,60 @@ static int xe_bo_apply_to_pinned(struct xe_device *xe,
}
/**
* xe_bo_evict_all - evict all BOs from VRAM
*
* xe_bo_notifier_prepare_all_pinned() - Pre-allocate the backing pages for all
* pinned VRAM objects which need to be saved.
* @xe: xe device
*
* Evict non-pinned user BOs first (via GPU), evict pinned external BOs next
* (via GPU), wait for evictions, and finally evict pinned kernel BOs via CPU.
* All eviction magic done via TTM calls.
* Should be called from PM notifier when preparing for s3/s4.
*
* Return: 0 on success, negative error code on error.
*/
int xe_bo_notifier_prepare_all_pinned(struct xe_device *xe)
{
int ret;
ret = xe_bo_apply_to_pinned(xe, &xe->pinned.early.kernel_bo_present,
&xe->pinned.early.kernel_bo_present,
xe_bo_notifier_prepare_pinned);
if (!ret)
ret = xe_bo_apply_to_pinned(xe, &xe->pinned.late.kernel_bo_present,
&xe->pinned.late.kernel_bo_present,
xe_bo_notifier_prepare_pinned);
return ret;
}
/**
* xe_bo_notifier_unprepare_all_pinned() - Remove the backing pages for all
* pinned VRAM objects which have been restored.
* @xe: xe device
*
* Should be called from PM notifier after exiting s3/s4 (either on success or
* failure).
*/
void xe_bo_notifier_unprepare_all_pinned(struct xe_device *xe)
{
(void)xe_bo_apply_to_pinned(xe, &xe->pinned.early.kernel_bo_present,
&xe->pinned.early.kernel_bo_present,
xe_bo_notifier_unprepare_pinned);
(void)xe_bo_apply_to_pinned(xe, &xe->pinned.late.kernel_bo_present,
&xe->pinned.late.kernel_bo_present,
xe_bo_notifier_unprepare_pinned);
}
/**
* xe_bo_evict_all_user - evict all non-pinned user BOs from VRAM
* @xe: xe device
*
* Evict non-pinned user BOs (via GPU).
*
* Evict == move VRAM BOs to temporary (typically system) memory.
*
* This function should be called before the device goes into a suspend state
* where the VRAM loses power.
*/
int xe_bo_evict_all(struct xe_device *xe)
int xe_bo_evict_all_user(struct xe_device *xe)
{
struct ttm_device *bdev = &xe->ttm;
struct xe_tile *tile;
u32 mem_type;
u8 id;
int ret;
/* User memory */
@@ -91,9 +132,34 @@ int xe_bo_evict_all(struct xe_device *xe)
}
}
ret = xe_bo_apply_to_pinned(xe, &xe->pinned.late.external,
&xe->pinned.late.external,
xe_bo_evict_pinned);
return 0;
}
/**
* xe_bo_evict_all - evict all BOs from VRAM
* @xe: xe device
*
* Evict non-pinned user BOs first (via GPU), evict pinned external BOs next
* (via GPU), wait for evictions, and finally evict pinned kernel BOs via CPU.
* All eviction magic done via TTM calls.
*
* Evict == move VRAM BOs to temporary (typically system) memory.
*
* This function should be called before the device goes into a suspend state
* where the VRAM loses power.
*/
int xe_bo_evict_all(struct xe_device *xe)
{
struct xe_tile *tile;
u8 id;
int ret;
ret = xe_bo_evict_all_user(xe);
if (ret)
return ret;
ret = xe_bo_apply_to_pinned(xe, &xe->pinned.late.kernel_bo_present,
&xe->pinned.late.evicted, xe_bo_evict_pinned);
if (!ret)
ret = xe_bo_apply_to_pinned(xe, &xe->pinned.late.kernel_bo_present,

View File

@@ -9,6 +9,9 @@
struct xe_device;
int xe_bo_evict_all(struct xe_device *xe);
int xe_bo_evict_all_user(struct xe_device *xe);
int xe_bo_notifier_prepare_all_pinned(struct xe_device *xe);
void xe_bo_notifier_unprepare_all_pinned(struct xe_device *xe);
int xe_bo_restore_early(struct xe_device *xe);
int xe_bo_restore_late(struct xe_device *xe);

View File

@@ -30,6 +30,8 @@ struct xe_bo {
struct ttm_buffer_object ttm;
/** @backup_obj: The backup object when pinned and suspended (vram only) */
struct xe_bo *backup_obj;
/** @parent_obj: Ref to parent bo if this a backup_obj */
struct xe_bo *parent_obj;
/** @size: Size of this buffer object */
size_t size;
/** @flags: flags for this buffer object */

View File

@@ -80,7 +80,8 @@ static struct xe_guc *exec_queue_to_guc(struct xe_exec_queue *q)
return &q->gt->uc.guc;
}
static ssize_t __xe_devcoredump_read(char *buffer, size_t count,
static ssize_t __xe_devcoredump_read(char *buffer, ssize_t count,
ssize_t start,
struct xe_devcoredump *coredump)
{
struct xe_device *xe;
@@ -94,7 +95,7 @@ static ssize_t __xe_devcoredump_read(char *buffer, size_t count,
ss = &coredump->snapshot;
iter.data = buffer;
iter.start = 0;
iter.start = start;
iter.remain = count;
p = drm_coredump_printer(&iter);
@@ -168,6 +169,8 @@ static void xe_devcoredump_snapshot_free(struct xe_devcoredump_snapshot *ss)
ss->vm = NULL;
}
#define XE_DEVCOREDUMP_CHUNK_MAX (SZ_512M + SZ_1G)
static ssize_t xe_devcoredump_read(char *buffer, loff_t offset,
size_t count, void *data, size_t datalen)
{
@@ -183,6 +186,9 @@ static ssize_t xe_devcoredump_read(char *buffer, loff_t offset,
/* Ensure delayed work is captured before continuing */
flush_work(&ss->work);
if (ss->read.size > XE_DEVCOREDUMP_CHUNK_MAX)
xe_pm_runtime_get(gt_to_xe(ss->gt));
mutex_lock(&coredump->lock);
if (!ss->read.buffer) {
@@ -195,12 +201,26 @@ static ssize_t xe_devcoredump_read(char *buffer, loff_t offset,
return 0;
}
if (offset >= ss->read.chunk_position + XE_DEVCOREDUMP_CHUNK_MAX ||
offset < ss->read.chunk_position) {
ss->read.chunk_position =
ALIGN_DOWN(offset, XE_DEVCOREDUMP_CHUNK_MAX);
__xe_devcoredump_read(ss->read.buffer,
XE_DEVCOREDUMP_CHUNK_MAX,
ss->read.chunk_position, coredump);
}
byte_copied = count < ss->read.size - offset ? count :
ss->read.size - offset;
memcpy(buffer, ss->read.buffer + offset, byte_copied);
memcpy(buffer, ss->read.buffer +
(offset % XE_DEVCOREDUMP_CHUNK_MAX), byte_copied);
mutex_unlock(&coredump->lock);
if (ss->read.size > XE_DEVCOREDUMP_CHUNK_MAX)
xe_pm_runtime_put(gt_to_xe(ss->gt));
return byte_copied;
}
@@ -254,17 +274,32 @@ static void xe_devcoredump_deferred_snap_work(struct work_struct *work)
xe_guc_exec_queue_snapshot_capture_delayed(ss->ge);
xe_force_wake_put(gt_to_fw(ss->gt), fw_ref);
xe_pm_runtime_put(xe);
ss->read.chunk_position = 0;
/* Calculate devcoredump size */
ss->read.size = __xe_devcoredump_read(NULL, INT_MAX, coredump);
ss->read.size = __xe_devcoredump_read(NULL, LONG_MAX, 0, coredump);
ss->read.buffer = kvmalloc(ss->read.size, GFP_USER);
if (!ss->read.buffer)
return;
if (ss->read.size > XE_DEVCOREDUMP_CHUNK_MAX) {
ss->read.buffer = kvmalloc(XE_DEVCOREDUMP_CHUNK_MAX,
GFP_USER);
if (!ss->read.buffer)
goto put_pm;
__xe_devcoredump_read(ss->read.buffer, ss->read.size, coredump);
xe_devcoredump_snapshot_free(ss);
__xe_devcoredump_read(ss->read.buffer,
XE_DEVCOREDUMP_CHUNK_MAX,
0, coredump);
} else {
ss->read.buffer = kvmalloc(ss->read.size, GFP_USER);
if (!ss->read.buffer)
goto put_pm;
__xe_devcoredump_read(ss->read.buffer, ss->read.size, 0,
coredump);
xe_devcoredump_snapshot_free(ss);
}
put_pm:
xe_pm_runtime_put(xe);
}
static void devcoredump_snapshot(struct xe_devcoredump *coredump,
@@ -425,7 +460,7 @@ void xe_print_blob_ascii85(struct drm_printer *p, const char *prefix, char suffi
if (offset & 3)
drm_printf(p, "Offset not word aligned: %zu", offset);
line_buff = kzalloc(DMESG_MAX_LINE_LEN, GFP_KERNEL);
line_buff = kzalloc(DMESG_MAX_LINE_LEN, GFP_ATOMIC);
if (!line_buff) {
drm_printf(p, "Failed to allocate line buffer\n");
return;

View File

@@ -66,6 +66,8 @@ struct xe_devcoredump_snapshot {
struct {
/** @read.size: size of devcoredump in human readable format */
ssize_t size;
/** @read.chunk_position: position of devcoredump chunk */
ssize_t chunk_position;
/** @read.buffer: buffer of devcoredump in human readable format */
char *buffer;
} read;

View File

@@ -522,6 +522,9 @@ struct xe_device {
struct mutex lock;
} d3cold;
/** @pm_notifier: Our PM notifier to perform actions in response to various PM events. */
struct notifier_block pm_notifier;
/** @pmt: Support the PMT driver callback interface */
struct {
/** @pmt.lock: protect access for telemetry data */

View File

@@ -52,6 +52,8 @@ struct xe_eu_stall_data_stream {
struct xe_gt *gt;
struct xe_bo *bo;
/* Lock to protect data buffer pointers */
struct mutex xecore_buf_lock;
struct per_xecore_buf *xecore_buf;
struct {
bool reported_to_user;
@@ -208,6 +210,9 @@ int xe_eu_stall_init(struct xe_gt *gt)
struct xe_device *xe = gt_to_xe(gt);
int ret;
if (!xe_eu_stall_supported_on_platform(xe))
return 0;
gt->eu_stall = kzalloc(sizeof(*gt->eu_stall), GFP_KERNEL);
if (!gt->eu_stall) {
ret = -ENOMEM;
@@ -378,7 +383,7 @@ static bool eu_stall_data_buf_poll(struct xe_eu_stall_data_stream *stream)
u16 group, instance;
unsigned int xecore;
mutex_lock(&gt->eu_stall->stream_lock);
mutex_lock(&stream->xecore_buf_lock);
for_each_dss_steering(xecore, gt, group, instance) {
xecore_buf = &stream->xecore_buf[xecore];
read_ptr = xecore_buf->read;
@@ -396,7 +401,7 @@ static bool eu_stall_data_buf_poll(struct xe_eu_stall_data_stream *stream)
set_bit(xecore, stream->data_drop.mask);
xecore_buf->write = write_ptr;
}
mutex_unlock(&gt->eu_stall->stream_lock);
mutex_unlock(&stream->xecore_buf_lock);
return min_data_present;
}
@@ -511,11 +516,13 @@ static ssize_t xe_eu_stall_stream_read_locked(struct xe_eu_stall_data_stream *st
unsigned int xecore;
int ret = 0;
mutex_lock(&stream->xecore_buf_lock);
if (bitmap_weight(stream->data_drop.mask, XE_MAX_DSS_FUSE_BITS)) {
if (!stream->data_drop.reported_to_user) {
stream->data_drop.reported_to_user = true;
xe_gt_dbg(gt, "EU stall data dropped in XeCores: %*pb\n",
XE_MAX_DSS_FUSE_BITS, stream->data_drop.mask);
mutex_unlock(&stream->xecore_buf_lock);
return -EIO;
}
stream->data_drop.reported_to_user = false;
@@ -527,6 +534,7 @@ static ssize_t xe_eu_stall_stream_read_locked(struct xe_eu_stall_data_stream *st
if (ret || count == total_size)
break;
}
mutex_unlock(&stream->xecore_buf_lock);
return total_size ?: (ret ?: -EAGAIN);
}
@@ -583,6 +591,7 @@ static void xe_eu_stall_stream_free(struct xe_eu_stall_data_stream *stream)
{
struct xe_gt *gt = stream->gt;
mutex_destroy(&stream->xecore_buf_lock);
gt->eu_stall->stream = NULL;
kfree(stream);
}
@@ -718,6 +727,7 @@ static int xe_eu_stall_stream_init(struct xe_eu_stall_data_stream *stream,
}
init_waitqueue_head(&stream->poll_wq);
mutex_init(&stream->xecore_buf_lock);
INIT_DELAYED_WORK(&stream->buf_poll_work, eu_stall_data_buf_poll_work_fn);
stream->per_xecore_buf_size = per_xecore_buf_size;
stream->sampling_rate_mult = props->sampling_rate_mult;

View File

@@ -7,6 +7,7 @@
#define __XE_EU_STALL_H__
#include "xe_gt_types.h"
#include "xe_sriov.h"
size_t xe_eu_stall_get_per_xecore_buf_size(void);
size_t xe_eu_stall_data_record_size(struct xe_device *xe);
@@ -19,6 +20,6 @@ int xe_eu_stall_stream_open(struct drm_device *dev,
static inline bool xe_eu_stall_supported_on_platform(struct xe_device *xe)
{
return xe->info.platform == XE_PVC || GRAPHICS_VER(xe) >= 20;
return !IS_SRIOV_VF(xe) && (xe->info.platform == XE_PVC || GRAPHICS_VER(xe) >= 20);
}
#endif

View File

@@ -56,9 +56,10 @@ dev_to_xe(struct device *dev)
return gt_to_xe(kobj_to_gt(dev->kobj.parent));
}
static ssize_t act_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t act_freq_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
u32 freq;
@@ -68,11 +69,12 @@ static ssize_t act_freq_show(struct device *dev,
return sysfs_emit(buf, "%d\n", freq);
}
static DEVICE_ATTR_RO(act_freq);
static struct kobj_attribute attr_act_freq = __ATTR_RO(act_freq);
static ssize_t cur_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t cur_freq_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
u32 freq;
ssize_t ret;
@@ -85,11 +87,12 @@ static ssize_t cur_freq_show(struct device *dev,
return sysfs_emit(buf, "%d\n", freq);
}
static DEVICE_ATTR_RO(cur_freq);
static struct kobj_attribute attr_cur_freq = __ATTR_RO(cur_freq);
static ssize_t rp0_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t rp0_freq_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
u32 freq;
@@ -99,11 +102,12 @@ static ssize_t rp0_freq_show(struct device *dev,
return sysfs_emit(buf, "%d\n", freq);
}
static DEVICE_ATTR_RO(rp0_freq);
static struct kobj_attribute attr_rp0_freq = __ATTR_RO(rp0_freq);
static ssize_t rpe_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t rpe_freq_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
u32 freq;
@@ -113,11 +117,12 @@ static ssize_t rpe_freq_show(struct device *dev,
return sysfs_emit(buf, "%d\n", freq);
}
static DEVICE_ATTR_RO(rpe_freq);
static struct kobj_attribute attr_rpe_freq = __ATTR_RO(rpe_freq);
static ssize_t rpa_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t rpa_freq_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
u32 freq;
@@ -127,20 +132,22 @@ static ssize_t rpa_freq_show(struct device *dev,
return sysfs_emit(buf, "%d\n", freq);
}
static DEVICE_ATTR_RO(rpa_freq);
static struct kobj_attribute attr_rpa_freq = __ATTR_RO(rpa_freq);
static ssize_t rpn_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t rpn_freq_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
return sysfs_emit(buf, "%d\n", xe_guc_pc_get_rpn_freq(pc));
}
static DEVICE_ATTR_RO(rpn_freq);
static struct kobj_attribute attr_rpn_freq = __ATTR_RO(rpn_freq);
static ssize_t min_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t min_freq_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
u32 freq;
ssize_t ret;
@@ -154,9 +161,10 @@ static ssize_t min_freq_show(struct device *dev,
return sysfs_emit(buf, "%d\n", freq);
}
static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
const char *buff, size_t count)
static ssize_t min_freq_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buff, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
u32 freq;
ssize_t ret;
@@ -173,11 +181,12 @@ static ssize_t min_freq_store(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR_RW(min_freq);
static struct kobj_attribute attr_min_freq = __ATTR_RW(min_freq);
static ssize_t max_freq_show(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t max_freq_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
u32 freq;
ssize_t ret;
@@ -191,9 +200,10 @@ static ssize_t max_freq_show(struct device *dev,
return sysfs_emit(buf, "%d\n", freq);
}
static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
const char *buff, size_t count)
static ssize_t max_freq_store(struct kobject *kobj,
struct kobj_attribute *attr, const char *buff, size_t count)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_guc_pc *pc = dev_to_pc(dev);
u32 freq;
ssize_t ret;
@@ -210,17 +220,17 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR_RW(max_freq);
static struct kobj_attribute attr_max_freq = __ATTR_RW(max_freq);
static const struct attribute *freq_attrs[] = {
&dev_attr_act_freq.attr,
&dev_attr_cur_freq.attr,
&dev_attr_rp0_freq.attr,
&dev_attr_rpa_freq.attr,
&dev_attr_rpe_freq.attr,
&dev_attr_rpn_freq.attr,
&dev_attr_min_freq.attr,
&dev_attr_max_freq.attr,
&attr_act_freq.attr,
&attr_cur_freq.attr,
&attr_rp0_freq.attr,
&attr_rpa_freq.attr,
&attr_rpe_freq.attr,
&attr_rpn_freq.attr,
&attr_min_freq.attr,
&attr_max_freq.attr,
NULL
};

View File

@@ -249,9 +249,10 @@ int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p)
return 0;
}
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buff)
static ssize_t name_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt_idle *gtidle = dev_to_gtidle(dev);
struct xe_guc_pc *pc = gtidle_to_pc(gtidle);
ssize_t ret;
@@ -262,11 +263,12 @@ static ssize_t name_show(struct device *dev,
return ret;
}
static DEVICE_ATTR_RO(name);
static struct kobj_attribute name_attr = __ATTR_RO(name);
static ssize_t idle_status_show(struct device *dev,
struct device_attribute *attr, char *buff)
static ssize_t idle_status_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt_idle *gtidle = dev_to_gtidle(dev);
struct xe_guc_pc *pc = gtidle_to_pc(gtidle);
enum xe_gt_idle_state state;
@@ -277,6 +279,7 @@ static ssize_t idle_status_show(struct device *dev,
return sysfs_emit(buff, "%s\n", gt_idle_state_to_string(state));
}
static struct kobj_attribute idle_status_attr = __ATTR_RO(idle_status);
u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle)
{
@@ -291,10 +294,11 @@ u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle)
return residency;
}
static DEVICE_ATTR_RO(idle_status);
static ssize_t idle_residency_ms_show(struct device *dev,
struct device_attribute *attr, char *buff)
static ssize_t idle_residency_ms_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt_idle *gtidle = dev_to_gtidle(dev);
struct xe_guc_pc *pc = gtidle_to_pc(gtidle);
u64 residency;
@@ -305,12 +309,12 @@ static ssize_t idle_residency_ms_show(struct device *dev,
return sysfs_emit(buff, "%llu\n", residency);
}
static DEVICE_ATTR_RO(idle_residency_ms);
static struct kobj_attribute idle_residency_attr = __ATTR_RO(idle_residency_ms);
static const struct attribute *gt_idle_attrs[] = {
&dev_attr_name.attr,
&dev_attr_idle_status.attr,
&dev_attr_idle_residency_ms.attr,
&name_attr.attr,
&idle_status_attr.attr,
&idle_residency_attr.attr,
NULL,
};

View File

@@ -114,115 +114,115 @@ static u32 read_reason_vr_tdc(struct xe_gt *gt)
return tdc;
}
static ssize_t status_show(struct device *dev,
struct device_attribute *attr,
char *buff)
static ssize_t status_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt *gt = dev_to_gt(dev);
bool status = !!read_status(gt);
return sysfs_emit(buff, "%u\n", status);
}
static DEVICE_ATTR_RO(status);
static struct kobj_attribute attr_status = __ATTR_RO(status);
static ssize_t reason_pl1_show(struct device *dev,
struct device_attribute *attr,
char *buff)
static ssize_t reason_pl1_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt *gt = dev_to_gt(dev);
bool pl1 = !!read_reason_pl1(gt);
return sysfs_emit(buff, "%u\n", pl1);
}
static DEVICE_ATTR_RO(reason_pl1);
static struct kobj_attribute attr_reason_pl1 = __ATTR_RO(reason_pl1);
static ssize_t reason_pl2_show(struct device *dev,
struct device_attribute *attr,
char *buff)
static ssize_t reason_pl2_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt *gt = dev_to_gt(dev);
bool pl2 = !!read_reason_pl2(gt);
return sysfs_emit(buff, "%u\n", pl2);
}
static DEVICE_ATTR_RO(reason_pl2);
static struct kobj_attribute attr_reason_pl2 = __ATTR_RO(reason_pl2);
static ssize_t reason_pl4_show(struct device *dev,
struct device_attribute *attr,
char *buff)
static ssize_t reason_pl4_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt *gt = dev_to_gt(dev);
bool pl4 = !!read_reason_pl4(gt);
return sysfs_emit(buff, "%u\n", pl4);
}
static DEVICE_ATTR_RO(reason_pl4);
static struct kobj_attribute attr_reason_pl4 = __ATTR_RO(reason_pl4);
static ssize_t reason_thermal_show(struct device *dev,
struct device_attribute *attr,
char *buff)
static ssize_t reason_thermal_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt *gt = dev_to_gt(dev);
bool thermal = !!read_reason_thermal(gt);
return sysfs_emit(buff, "%u\n", thermal);
}
static DEVICE_ATTR_RO(reason_thermal);
static struct kobj_attribute attr_reason_thermal = __ATTR_RO(reason_thermal);
static ssize_t reason_prochot_show(struct device *dev,
struct device_attribute *attr,
char *buff)
static ssize_t reason_prochot_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt *gt = dev_to_gt(dev);
bool prochot = !!read_reason_prochot(gt);
return sysfs_emit(buff, "%u\n", prochot);
}
static DEVICE_ATTR_RO(reason_prochot);
static struct kobj_attribute attr_reason_prochot = __ATTR_RO(reason_prochot);
static ssize_t reason_ratl_show(struct device *dev,
struct device_attribute *attr,
char *buff)
static ssize_t reason_ratl_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt *gt = dev_to_gt(dev);
bool ratl = !!read_reason_ratl(gt);
return sysfs_emit(buff, "%u\n", ratl);
}
static DEVICE_ATTR_RO(reason_ratl);
static struct kobj_attribute attr_reason_ratl = __ATTR_RO(reason_ratl);
static ssize_t reason_vr_thermalert_show(struct device *dev,
struct device_attribute *attr,
char *buff)
static ssize_t reason_vr_thermalert_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt *gt = dev_to_gt(dev);
bool thermalert = !!read_reason_vr_thermalert(gt);
return sysfs_emit(buff, "%u\n", thermalert);
}
static DEVICE_ATTR_RO(reason_vr_thermalert);
static struct kobj_attribute attr_reason_vr_thermalert = __ATTR_RO(reason_vr_thermalert);
static ssize_t reason_vr_tdc_show(struct device *dev,
struct device_attribute *attr,
char *buff)
static ssize_t reason_vr_tdc_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buff)
{
struct device *dev = kobj_to_dev(kobj);
struct xe_gt *gt = dev_to_gt(dev);
bool tdc = !!read_reason_vr_tdc(gt);
return sysfs_emit(buff, "%u\n", tdc);
}
static DEVICE_ATTR_RO(reason_vr_tdc);
static struct kobj_attribute attr_reason_vr_tdc = __ATTR_RO(reason_vr_tdc);
static struct attribute *throttle_attrs[] = {
&dev_attr_status.attr,
&dev_attr_reason_pl1.attr,
&dev_attr_reason_pl2.attr,
&dev_attr_reason_pl4.attr,
&dev_attr_reason_thermal.attr,
&dev_attr_reason_prochot.attr,
&dev_attr_reason_ratl.attr,
&dev_attr_reason_vr_thermalert.attr,
&dev_attr_reason_vr_tdc.attr,
&attr_status.attr,
&attr_reason_pl1.attr,
&attr_reason_pl2.attr,
&attr_reason_pl4.attr,
&attr_reason_thermal.attr,
&attr_reason_prochot.attr,
&attr_reason_ratl.attr,
&attr_reason_vr_thermalert.attr,
&attr_reason_vr_tdc.attr,
NULL
};

View File

@@ -1394,6 +1394,7 @@ int xe_guc_mmio_send_recv(struct xe_guc *guc, const u32 *request,
/* Use data from the GuC response as our return value */
return FIELD_GET(GUC_HXG_RESPONSE_MSG_0_DATA0, header);
}
ALLOW_ERROR_INJECTION(xe_guc_mmio_send_recv, ERRNO);
int xe_guc_mmio_send(struct xe_guc *guc, const u32 *request, u32 len)
{

View File

@@ -105,49 +105,49 @@ struct __guc_capture_parsed_output {
* 3. Incorrect order will trigger XE_WARN.
*/
#define COMMON_XELP_BASE_GLOBAL \
{ FORCEWAKE_GT, REG_32BIT, 0, 0, "FORCEWAKE_GT"}
{ FORCEWAKE_GT, REG_32BIT, 0, 0, 0, "FORCEWAKE_GT"}
#define COMMON_BASE_ENGINE_INSTANCE \
{ RING_HWSTAM(0), REG_32BIT, 0, 0, "HWSTAM"}, \
{ RING_HWS_PGA(0), REG_32BIT, 0, 0, "RING_HWS_PGA"}, \
{ RING_HEAD(0), REG_32BIT, 0, 0, "RING_HEAD"}, \
{ RING_TAIL(0), REG_32BIT, 0, 0, "RING_TAIL"}, \
{ RING_CTL(0), REG_32BIT, 0, 0, "RING_CTL"}, \
{ RING_MI_MODE(0), REG_32BIT, 0, 0, "RING_MI_MODE"}, \
{ RING_MODE(0), REG_32BIT, 0, 0, "RING_MODE"}, \
{ RING_ESR(0), REG_32BIT, 0, 0, "RING_ESR"}, \
{ RING_EMR(0), REG_32BIT, 0, 0, "RING_EMR"}, \
{ RING_EIR(0), REG_32BIT, 0, 0, "RING_EIR"}, \
{ RING_IMR(0), REG_32BIT, 0, 0, "RING_IMR"}, \
{ RING_IPEHR(0), REG_32BIT, 0, 0, "IPEHR"}, \
{ RING_INSTDONE(0), REG_32BIT, 0, 0, "RING_INSTDONE"}, \
{ INDIRECT_RING_STATE(0), REG_32BIT, 0, 0, "INDIRECT_RING_STATE"}, \
{ RING_ACTHD(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
{ RING_ACTHD_UDW(0), REG_64BIT_HI_DW, 0, 0, "ACTHD"}, \
{ RING_BBADDR(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
{ RING_BBADDR_UDW(0), REG_64BIT_HI_DW, 0, 0, "RING_BBADDR"}, \
{ RING_START(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
{ RING_START_UDW(0), REG_64BIT_HI_DW, 0, 0, "RING_START"}, \
{ RING_DMA_FADD(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
{ RING_DMA_FADD_UDW(0), REG_64BIT_HI_DW, 0, 0, "RING_DMA_FADD"}, \
{ RING_EXECLIST_STATUS_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
{ RING_EXECLIST_STATUS_HI(0), REG_64BIT_HI_DW, 0, 0, "RING_EXECLIST_STATUS"}, \
{ RING_EXECLIST_SQ_CONTENTS_LO(0), REG_64BIT_LOW_DW, 0, 0, NULL}, \
{ RING_EXECLIST_SQ_CONTENTS_HI(0), REG_64BIT_HI_DW, 0, 0, "RING_EXECLIST_SQ_CONTENTS"}
{ RING_HWSTAM(0), REG_32BIT, 0, 0, 0, "HWSTAM"}, \
{ RING_HWS_PGA(0), REG_32BIT, 0, 0, 0, "RING_HWS_PGA"}, \
{ RING_HEAD(0), REG_32BIT, 0, 0, 0, "RING_HEAD"}, \
{ RING_TAIL(0), REG_32BIT, 0, 0, 0, "RING_TAIL"}, \
{ RING_CTL(0), REG_32BIT, 0, 0, 0, "RING_CTL"}, \
{ RING_MI_MODE(0), REG_32BIT, 0, 0, 0, "RING_MI_MODE"}, \
{ RING_MODE(0), REG_32BIT, 0, 0, 0, "RING_MODE"}, \
{ RING_ESR(0), REG_32BIT, 0, 0, 0, "RING_ESR"}, \
{ RING_EMR(0), REG_32BIT, 0, 0, 0, "RING_EMR"}, \
{ RING_EIR(0), REG_32BIT, 0, 0, 0, "RING_EIR"}, \
{ RING_IMR(0), REG_32BIT, 0, 0, 0, "RING_IMR"}, \
{ RING_IPEHR(0), REG_32BIT, 0, 0, 0, "IPEHR"}, \
{ RING_INSTDONE(0), REG_32BIT, 0, 0, 0, "RING_INSTDONE"}, \
{ INDIRECT_RING_STATE(0), REG_32BIT, 0, 0, 0, "INDIRECT_RING_STATE"}, \
{ RING_ACTHD(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
{ RING_ACTHD_UDW(0), REG_64BIT_HI_DW, 0, 0, 0, "ACTHD"}, \
{ RING_BBADDR(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
{ RING_BBADDR_UDW(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_BBADDR"}, \
{ RING_START(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
{ RING_START_UDW(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_START"}, \
{ RING_DMA_FADD(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
{ RING_DMA_FADD_UDW(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_DMA_FADD"}, \
{ RING_EXECLIST_STATUS_LO(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
{ RING_EXECLIST_STATUS_HI(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_EXECLIST_STATUS"}, \
{ RING_EXECLIST_SQ_CONTENTS_LO(0), REG_64BIT_LOW_DW, 0, 0, 0, NULL}, \
{ RING_EXECLIST_SQ_CONTENTS_HI(0), REG_64BIT_HI_DW, 0, 0, 0, "RING_EXECLIST_SQ_CONTENTS"}
#define COMMON_XELP_RC_CLASS \
{ RCU_MODE, REG_32BIT, 0, 0, "RCU_MODE"}
{ RCU_MODE, REG_32BIT, 0, 0, 0, "RCU_MODE"}
#define COMMON_XELP_RC_CLASS_INSTDONE \
{ SC_INSTDONE, REG_32BIT, 0, 0, "SC_INSTDONE"}, \
{ SC_INSTDONE_EXTRA, REG_32BIT, 0, 0, "SC_INSTDONE_EXTRA"}, \
{ SC_INSTDONE_EXTRA2, REG_32BIT, 0, 0, "SC_INSTDONE_EXTRA2"}
{ SC_INSTDONE, REG_32BIT, 0, 0, 0, "SC_INSTDONE"}, \
{ SC_INSTDONE_EXTRA, REG_32BIT, 0, 0, 0, "SC_INSTDONE_EXTRA"}, \
{ SC_INSTDONE_EXTRA2, REG_32BIT, 0, 0, 0, "SC_INSTDONE_EXTRA2"}
#define XELP_VEC_CLASS_REGS \
{ SFC_DONE(0), 0, 0, 0, "SFC_DONE[0]"}, \
{ SFC_DONE(1), 0, 0, 0, "SFC_DONE[1]"}, \
{ SFC_DONE(2), 0, 0, 0, "SFC_DONE[2]"}, \
{ SFC_DONE(3), 0, 0, 0, "SFC_DONE[3]"}
{ SFC_DONE(0), 0, 0, 0, 0, "SFC_DONE[0]"}, \
{ SFC_DONE(1), 0, 0, 0, 0, "SFC_DONE[1]"}, \
{ SFC_DONE(2), 0, 0, 0, 0, "SFC_DONE[2]"}, \
{ SFC_DONE(3), 0, 0, 0, 0, "SFC_DONE[3]"}
/* XE_LP Global */
static const struct __guc_mmio_reg_descr xe_lp_global_regs[] = {
@@ -352,15 +352,16 @@ static const struct __ext_steer_reg xehpg_extregs[] = {
static void __fill_ext_reg(struct __guc_mmio_reg_descr *ext,
const struct __ext_steer_reg *extlist,
int slice_id, int subslice_id)
u32 dss_id, u16 slice_id, u16 subslice_id)
{
if (!ext || !extlist)
return;
ext->reg = XE_REG(extlist->reg.__reg.addr);
ext->flags = FIELD_PREP(GUC_REGSET_STEERING_NEEDED, 1);
ext->flags = FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id);
ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_GROUP, slice_id);
ext->flags |= FIELD_PREP(GUC_REGSET_STEERING_INSTANCE, subslice_id);
ext->dss_id = dss_id;
ext->regname = extlist->name;
}
@@ -397,7 +398,7 @@ static void guc_capture_alloc_steered_lists(struct xe_guc *guc)
{
struct xe_gt *gt = guc_to_gt(guc);
u16 slice, subslice;
int iter, i, total = 0;
int dss, i, total = 0;
const struct __guc_mmio_reg_descr_group *lists = guc->capture->reglists;
const struct __guc_mmio_reg_descr_group *list;
struct __guc_mmio_reg_descr_group *extlists;
@@ -454,15 +455,15 @@ static void guc_capture_alloc_steered_lists(struct xe_guc *guc)
/* For steering registers, the list is generated at run-time */
extarray = (struct __guc_mmio_reg_descr *)extlists[0].list;
for_each_dss_steering(iter, gt, slice, subslice) {
for_each_dss_steering(dss, gt, slice, subslice) {
for (i = 0; i < ARRAY_SIZE(xe_extregs); ++i) {
__fill_ext_reg(extarray, &xe_extregs[i], slice, subslice);
__fill_ext_reg(extarray, &xe_extregs[i], dss, slice, subslice);
++extarray;
}
if (has_xehpg_extregs)
for (i = 0; i < ARRAY_SIZE(xehpg_extregs); ++i) {
__fill_ext_reg(extarray, &xehpg_extregs[i], slice, subslice);
__fill_ext_reg(extarray, &xehpg_extregs[i], dss, slice, subslice);
++extarray;
}
}
@@ -1672,18 +1673,16 @@ snapshot_print_by_list_order(struct xe_hw_engine_snapshot *snapshot, struct drm_
{
struct xe_gt *gt = snapshot->hwe->gt;
struct xe_device *xe = gt_to_xe(gt);
struct xe_guc *guc = &gt->uc.guc;
struct xe_devcoredump *devcoredump = &xe->devcoredump;
struct xe_devcoredump_snapshot *devcore_snapshot = &devcoredump->snapshot;
struct gcap_reg_list_info *reginfo = NULL;
u32 i, last_value = 0;
bool is_ext, low32_ready = false;
bool low32_ready = false;
if (!list || !list->list || list->num_regs == 0)
return;
XE_WARN_ON(!devcore_snapshot->matched_node);
is_ext = list == guc->capture->extlists;
reginfo = &devcore_snapshot->matched_node->reginfo[type];
/*
@@ -1749,17 +1748,12 @@ snapshot_print_by_list_order(struct xe_hw_engine_snapshot *snapshot, struct drm_
*/
XE_WARN_ON(low32_ready);
if (is_ext) {
int dss, group, instance;
group = FIELD_GET(GUC_REGSET_STEERING_GROUP, reg_desc->flags);
instance = FIELD_GET(GUC_REGSET_STEERING_INSTANCE, reg_desc->flags);
dss = xe_gt_mcr_steering_info_to_dss_id(gt, group, instance);
drm_printf(p, "\t%s[%u]: 0x%08x\n", reg_desc->regname, dss, value);
} else {
if (FIELD_GET(GUC_REGSET_STEERING_NEEDED, reg_desc->flags))
drm_printf(p, "\t%s[%u]: 0x%08x\n", reg_desc->regname,
reg_desc->dss_id, value);
else
drm_printf(p, "\t%s: 0x%08x\n", reg_desc->regname, value);
}
break;
}
}

View File

@@ -39,6 +39,8 @@ struct __guc_mmio_reg_descr {
u32 flags;
/** @mask: The mask to apply */
u32 mask;
/** @dss_id: Cached index for steered registers */
u32 dss_id;
/** @regname: Name of the register */
const char *regname;
};

View File

@@ -1089,6 +1089,7 @@ int xe_guc_ct_send_recv(struct xe_guc_ct *ct, const u32 *action, u32 len,
KUNIT_STATIC_STUB_REDIRECT(xe_guc_ct_send_recv, ct, action, len, response_buffer);
return guc_ct_send_recv(ct, action, len, response_buffer, false);
}
ALLOW_ERROR_INJECTION(xe_guc_ct_send_recv, ERRNO);
int xe_guc_ct_send_recv_no_fail(struct xe_guc_ct *ct, const u32 *action,
u32 len, u32 *response_buffer)

View File

@@ -304,6 +304,8 @@ static void engine_activity_set_cpu_ts(struct xe_guc *guc, unsigned int index)
struct engine_activity_group *eag = &engine_activity->eag[index];
int i, j;
xe_gt_assert(guc_to_gt(guc), index < engine_activity->num_activity_group);
for (i = 0; i < GUC_MAX_ENGINE_CLASSES; i++)
for (j = 0; j < GUC_MAX_INSTANCES_PER_CLASS; j++)
eag->engine[i][j].last_cpu_ts = ktime_get();
@@ -374,8 +376,9 @@ static int engine_activity_enable_function_stats(struct xe_guc *guc, int num_vfs
return ret;
}
for (i = 0; i < engine_activity->num_functions; i++)
engine_activity_set_cpu_ts(guc, i + 1);
/* skip PF as it was already setup */
for (i = 1; i < engine_activity->num_functions; i++)
engine_activity_set_cpu_ts(guc, i);
return 0;
}

View File

@@ -669,6 +669,7 @@ static void emit_copy(struct xe_gt *gt, struct xe_bb *bb,
u32 mocs = 0;
u32 tile_y = 0;
xe_gt_assert(gt, !(pitch & 3));
xe_gt_assert(gt, size / pitch <= S16_MAX);
xe_gt_assert(gt, pitch / 4 <= S16_MAX);
xe_gt_assert(gt, pitch <= U16_MAX);
@@ -1546,7 +1547,6 @@ void xe_migrate_wait(struct xe_migrate *m)
dma_fence_wait(m->fence, false);
}
#if IS_ENABLED(CONFIG_DRM_XE_DEVMEM_MIRROR)
static u32 pte_update_cmd_size(u64 size)
{
u32 num_dword;
@@ -1604,8 +1604,12 @@ enum xe_migrate_copy_dir {
XE_MIGRATE_COPY_TO_SRAM,
};
#define XE_CACHELINE_BYTES 64ull
#define XE_CACHELINE_MASK (XE_CACHELINE_BYTES - 1)
static struct dma_fence *xe_migrate_vram(struct xe_migrate *m,
unsigned long npages,
unsigned long len,
unsigned long sram_offset,
dma_addr_t *sram_addr, u64 vram_addr,
const enum xe_migrate_copy_dir dir)
{
@@ -1615,17 +1619,21 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m,
struct dma_fence *fence = NULL;
u32 batch_size = 2;
u64 src_L0_ofs, dst_L0_ofs;
u64 round_update_size;
struct xe_sched_job *job;
struct xe_bb *bb;
u32 update_idx, pt_slot = 0;
unsigned long npages = DIV_ROUND_UP(len + sram_offset, PAGE_SIZE);
unsigned int pitch = len >= PAGE_SIZE && !(len & ~PAGE_MASK) ?
PAGE_SIZE : 4;
int err;
if (npages * PAGE_SIZE > MAX_PREEMPTDISABLE_TRANSFER)
return ERR_PTR(-EINVAL);
if (drm_WARN_ON(&xe->drm, (len & XE_CACHELINE_MASK) ||
(sram_offset | vram_addr) & XE_CACHELINE_MASK))
return ERR_PTR(-EOPNOTSUPP);
round_update_size = npages * PAGE_SIZE;
batch_size += pte_update_cmd_size(round_update_size);
xe_assert(xe, npages * PAGE_SIZE <= MAX_PREEMPTDISABLE_TRANSFER);
batch_size += pte_update_cmd_size(len);
batch_size += EMIT_COPY_DW;
bb = xe_bb_new(gt, batch_size, use_usm_batch);
@@ -1635,22 +1643,21 @@ static struct dma_fence *xe_migrate_vram(struct xe_migrate *m,
}
build_pt_update_batch_sram(m, bb, pt_slot * XE_PAGE_SIZE,
sram_addr, round_update_size);
sram_addr, len + sram_offset);
if (dir == XE_MIGRATE_COPY_TO_VRAM) {
src_L0_ofs = xe_migrate_vm_addr(pt_slot, 0);
src_L0_ofs = xe_migrate_vm_addr(pt_slot, 0) + sram_offset;
dst_L0_ofs = xe_migrate_vram_ofs(xe, vram_addr, false);
} else {
src_L0_ofs = xe_migrate_vram_ofs(xe, vram_addr, false);
dst_L0_ofs = xe_migrate_vm_addr(pt_slot, 0);
dst_L0_ofs = xe_migrate_vm_addr(pt_slot, 0) + sram_offset;
}
bb->cs[bb->len++] = MI_BATCH_BUFFER_END;
update_idx = bb->len;
emit_copy(gt, bb, src_L0_ofs, dst_L0_ofs, round_update_size,
XE_PAGE_SIZE);
emit_copy(gt, bb, src_L0_ofs, dst_L0_ofs, len, pitch);
job = xe_bb_create_migration_job(m->q, bb,
xe_migrate_batch_base(m, use_usm_batch),
@@ -1698,7 +1705,7 @@ struct dma_fence *xe_migrate_to_vram(struct xe_migrate *m,
dma_addr_t *src_addr,
u64 dst_addr)
{
return xe_migrate_vram(m, npages, src_addr, dst_addr,
return xe_migrate_vram(m, npages * PAGE_SIZE, 0, src_addr, dst_addr,
XE_MIGRATE_COPY_TO_VRAM);
}
@@ -1719,11 +1726,192 @@ struct dma_fence *xe_migrate_from_vram(struct xe_migrate *m,
u64 src_addr,
dma_addr_t *dst_addr)
{
return xe_migrate_vram(m, npages, dst_addr, src_addr,
return xe_migrate_vram(m, npages * PAGE_SIZE, 0, dst_addr, src_addr,
XE_MIGRATE_COPY_TO_SRAM);
}
#endif
static void xe_migrate_dma_unmap(struct xe_device *xe, dma_addr_t *dma_addr,
int len, int write)
{
unsigned long i, npages = DIV_ROUND_UP(len, PAGE_SIZE);
for (i = 0; i < npages; ++i) {
if (!dma_addr[i])
break;
dma_unmap_page(xe->drm.dev, dma_addr[i], PAGE_SIZE,
write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
}
kfree(dma_addr);
}
static dma_addr_t *xe_migrate_dma_map(struct xe_device *xe,
void *buf, int len, int write)
{
dma_addr_t *dma_addr;
unsigned long i, npages = DIV_ROUND_UP(len, PAGE_SIZE);
dma_addr = kcalloc(npages, sizeof(*dma_addr), GFP_KERNEL);
if (!dma_addr)
return ERR_PTR(-ENOMEM);
for (i = 0; i < npages; ++i) {
dma_addr_t addr;
struct page *page;
if (is_vmalloc_addr(buf))
page = vmalloc_to_page(buf);
else
page = virt_to_page(buf);
addr = dma_map_page(xe->drm.dev,
page, 0, PAGE_SIZE,
write ? DMA_TO_DEVICE :
DMA_FROM_DEVICE);
if (dma_mapping_error(xe->drm.dev, addr))
goto err_fault;
dma_addr[i] = addr;
buf += PAGE_SIZE;
}
return dma_addr;
err_fault:
xe_migrate_dma_unmap(xe, dma_addr, len, write);
return ERR_PTR(-EFAULT);
}
/**
* xe_migrate_access_memory - Access memory of a BO via GPU
*
* @m: The migration context.
* @bo: buffer object
* @offset: access offset into buffer object
* @buf: pointer to caller memory to read into or write from
* @len: length of access
* @write: write access
*
* Access memory of a BO via GPU either reading in or writing from a passed in
* pointer. Pointer is dma mapped for GPU access and GPU commands are issued to
* read to or write from pointer.
*
* Returns:
* 0 if successful, negative error code on failure.
*/
int xe_migrate_access_memory(struct xe_migrate *m, struct xe_bo *bo,
unsigned long offset, void *buf, int len,
int write)
{
struct xe_tile *tile = m->tile;
struct xe_device *xe = tile_to_xe(tile);
struct xe_res_cursor cursor;
struct dma_fence *fence = NULL;
dma_addr_t *dma_addr;
unsigned long page_offset = (unsigned long)buf & ~PAGE_MASK;
int bytes_left = len, current_page = 0;
void *orig_buf = buf;
xe_bo_assert_held(bo);
/* Use bounce buffer for small access and unaligned access */
if (len & XE_CACHELINE_MASK ||
((uintptr_t)buf | offset) & XE_CACHELINE_MASK) {
int buf_offset = 0;
/*
* Less than ideal for large unaligned access but this should be
* fairly rare, can fixup if this becomes common.
*/
do {
u8 bounce[XE_CACHELINE_BYTES];
void *ptr = (void *)bounce;
int err;
int copy_bytes = min_t(int, bytes_left,
XE_CACHELINE_BYTES -
(offset & XE_CACHELINE_MASK));
int ptr_offset = offset & XE_CACHELINE_MASK;
err = xe_migrate_access_memory(m, bo,
offset &
~XE_CACHELINE_MASK,
(void *)ptr,
sizeof(bounce), 0);
if (err)
return err;
if (write) {
memcpy(ptr + ptr_offset, buf + buf_offset, copy_bytes);
err = xe_migrate_access_memory(m, bo,
offset & ~XE_CACHELINE_MASK,
(void *)ptr,
sizeof(bounce), 0);
if (err)
return err;
} else {
memcpy(buf + buf_offset, ptr + ptr_offset,
copy_bytes);
}
bytes_left -= copy_bytes;
buf_offset += copy_bytes;
offset += copy_bytes;
} while (bytes_left);
return 0;
}
dma_addr = xe_migrate_dma_map(xe, buf, len + page_offset, write);
if (IS_ERR(dma_addr))
return PTR_ERR(dma_addr);
xe_res_first(bo->ttm.resource, offset, bo->size - offset, &cursor);
do {
struct dma_fence *__fence;
u64 vram_addr = vram_region_gpu_offset(bo->ttm.resource) +
cursor.start;
int current_bytes;
if (cursor.size > MAX_PREEMPTDISABLE_TRANSFER)
current_bytes = min_t(int, bytes_left,
MAX_PREEMPTDISABLE_TRANSFER);
else
current_bytes = min_t(int, bytes_left, cursor.size);
if (fence)
dma_fence_put(fence);
__fence = xe_migrate_vram(m, current_bytes,
(unsigned long)buf & ~PAGE_MASK,
dma_addr + current_page,
vram_addr, write ?
XE_MIGRATE_COPY_TO_VRAM :
XE_MIGRATE_COPY_TO_SRAM);
if (IS_ERR(__fence)) {
if (fence)
dma_fence_wait(fence, false);
fence = __fence;
goto out_err;
}
fence = __fence;
buf += current_bytes;
offset += current_bytes;
current_page = (int)(buf - orig_buf) / PAGE_SIZE;
bytes_left -= current_bytes;
if (bytes_left)
xe_res_next(&cursor, current_bytes);
} while (bytes_left);
dma_fence_wait(fence, false);
dma_fence_put(fence);
out_err:
xe_migrate_dma_unmap(xe, dma_addr, len + page_offset, write);
return IS_ERR(fence) ? PTR_ERR(fence) : 0;
}
#if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST)
#include "tests/xe_migrate.c"

View File

@@ -112,6 +112,10 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m,
struct ttm_resource *dst,
bool copy_only_ccs);
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 | \

View File

@@ -742,7 +742,7 @@ static void xe_pci_remove(struct pci_dev *pdev)
return;
xe_device_remove(xe);
xe_pm_runtime_fini(xe);
xe_pm_fini(xe);
}
/*

View File

@@ -7,6 +7,7 @@
#include "xe_device.h"
#include "xe_gt_sriov_pf_config.h"
#include "xe_gt_sriov_pf_control.h"
#include "xe_gt_sriov_printk.h"
#include "xe_guc_engine_activity.h"
#include "xe_pci_sriov.h"
#include "xe_pm.h"
@@ -121,8 +122,8 @@ static void pf_engine_activity_stats(struct xe_device *xe, unsigned int num_vfs,
for_each_gt(gt, xe, id) {
ret = xe_guc_engine_activity_function_stats(&gt->uc.guc, num_vfs, enable);
if (ret)
xe_sriov_info(xe, "Failed to %s engine activity function stats (%pe)\n",
str_enable_disable(enable), ERR_PTR(ret));
xe_gt_sriov_info(gt, "Failed to %s engine activity function stats (%pe)\n",
str_enable_disable(enable), ERR_PTR(ret));
}
}

View File

@@ -286,6 +286,42 @@ static u32 vram_threshold_value(struct xe_device *xe)
return DEFAULT_VRAM_THRESHOLD;
}
static int xe_pm_notifier_callback(struct notifier_block *nb,
unsigned long action, void *data)
{
struct xe_device *xe = container_of(nb, struct xe_device, pm_notifier);
int err = 0;
switch (action) {
case PM_HIBERNATION_PREPARE:
case PM_SUSPEND_PREPARE:
xe_pm_runtime_get(xe);
err = xe_bo_evict_all_user(xe);
if (err) {
drm_dbg(&xe->drm, "Notifier evict user failed (%d)\n", err);
xe_pm_runtime_put(xe);
break;
}
err = xe_bo_notifier_prepare_all_pinned(xe);
if (err) {
drm_dbg(&xe->drm, "Notifier prepare pin failed (%d)\n", err);
xe_pm_runtime_put(xe);
}
break;
case PM_POST_HIBERNATION:
case PM_POST_SUSPEND:
xe_bo_notifier_unprepare_all_pinned(xe);
xe_pm_runtime_put(xe);
break;
}
if (err)
return NOTIFY_BAD;
return NOTIFY_DONE;
}
/**
* xe_pm_init - Initialize Xe Power Management
* @xe: xe device instance
@@ -299,6 +335,11 @@ int xe_pm_init(struct xe_device *xe)
u32 vram_threshold;
int err;
xe->pm_notifier.notifier_call = xe_pm_notifier_callback;
err = register_pm_notifier(&xe->pm_notifier);
if (err)
return err;
/* For now suspend/resume is only allowed with GuC */
if (!xe_device_uc_enabled(xe))
return 0;
@@ -308,24 +349,23 @@ int xe_pm_init(struct xe_device *xe)
if (xe->d3cold.capable) {
err = xe_device_sysfs_init(xe);
if (err)
return err;
goto err_unregister;
vram_threshold = vram_threshold_value(xe);
err = xe_pm_set_vram_threshold(xe, vram_threshold);
if (err)
return err;
goto err_unregister;
}
xe_pm_runtime_init(xe);
return 0;
err_unregister:
unregister_pm_notifier(&xe->pm_notifier);
return err;
}
/**
* xe_pm_runtime_fini - Finalize Runtime PM
* @xe: xe device instance
*/
void xe_pm_runtime_fini(struct xe_device *xe)
static void xe_pm_runtime_fini(struct xe_device *xe)
{
struct device *dev = xe->drm.dev;
@@ -333,6 +373,18 @@ void xe_pm_runtime_fini(struct xe_device *xe)
pm_runtime_forbid(dev);
}
/**
* xe_pm_fini - Finalize PM
* @xe: xe device instance
*/
void xe_pm_fini(struct xe_device *xe)
{
if (xe_device_uc_enabled(xe))
xe_pm_runtime_fini(xe);
unregister_pm_notifier(&xe->pm_notifier);
}
static void xe_pm_write_callback_task(struct xe_device *xe,
struct task_struct *task)
{

View File

@@ -17,7 +17,7 @@ int xe_pm_resume(struct xe_device *xe);
int xe_pm_init_early(struct xe_device *xe);
int xe_pm_init(struct xe_device *xe);
void xe_pm_runtime_fini(struct xe_device *xe);
void xe_pm_fini(struct xe_device *xe);
bool xe_pm_runtime_suspended(struct xe_device *xe);
int xe_pm_runtime_suspend(struct xe_device *xe);
int xe_pm_runtime_resume(struct xe_device *xe);

View File

@@ -66,9 +66,18 @@ static int pxp_terminate(struct seq_file *m, void *data)
{
struct xe_pxp *pxp = node_to_pxp(m->private);
struct drm_printer p = drm_seq_file_printer(m);
int ready = xe_pxp_get_readiness_status(pxp);
if (!xe_pxp_is_enabled(pxp))
return -ENODEV;
if (ready < 0)
return ready; /* disabled or error occurred */
else if (!ready)
return -EBUSY; /* init still in progress */
/* no need for a termination if PXP is not active */
if (pxp->status != XE_PXP_ACTIVE) {
drm_printf(&p, "PXP not active\n");
return 0;
}
/* simulate a termination interrupt */
spin_lock_irq(&pxp->xe->irq.lock);

View File

@@ -80,7 +80,7 @@ xe_svm_range_alloc(struct drm_gpusvm *gpusvm)
range = kzalloc(sizeof(*range), GFP_KERNEL);
if (!range)
return ERR_PTR(-ENOMEM);
return NULL;
INIT_LIST_HEAD(&range->garbage_collector_link);
xe_vm_get(gpusvm_to_vm(gpusvm));

View File

@@ -3866,6 +3866,9 @@ void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p)
}
drm_puts(p, "\n");
if (drm_coredump_printer_is_full(p))
return;
}
}

View File

@@ -344,6 +344,26 @@ drm_coredump_printer(struct drm_print_iterator *iter)
return p;
}
/**
* drm_coredump_printer_is_full() - DRM coredump printer output is full
* @p: DRM coredump printer
*
* DRM printer output is full, useful to short circuit coredump printing once
* printer is full.
*
* RETURNS:
* True if DRM coredump printer output buffer is full, False otherwise
*/
static inline bool drm_coredump_printer_is_full(struct drm_printer *p)
{
struct drm_print_iterator *iterator = p->arg;
if (p->printfn != __drm_printfn_coredump)
return true;
return !iterator->remain;
}
/**
* drm_seq_file_printer - construct a &drm_printer that outputs to &seq_file
* @f: the &struct seq_file to output to