Merge tag 'drm-xe-next-2026-01-15' of https://gitlab.freedesktop.org/drm/xe/kernel into drm-next

UAPI Changes:
 - Remove unused KEEP_ACTIVE flag in the new multi queue uAPI (Niranjana)
 - Expose new temperature attributes in HWMON (Karthik)

Driver Changes:
 - Force i2c into polling mode when in survivability (Raag)
 - Validate preferred system memory placement in xe_svm_range_validate (Brost)
 - Adjust page count tracepoints in shrinker (Brost)
 - Fix a couple drm_pagemap issues with multi-GPU (Brost)
 - Define GuC firmware for NVL-S (Roper)
 - Handle GT resume failure (Raag)
 - Improve wedged mode handling (Lukasz)
 - Add missing newlines to drm_warn messages (Osama)
 - Fix WQ_MEM_RECLAIM passed as max_active to alloc_workqueue (Marco)
 - Page-reclaim fixes and PRL stats addition (Brian)
 - Fix struct guc_lfd_file_header kernel-doc (Jani)
 - Allow compressible surfaces to be 1-way coherent (Xin)
 - Fix DRM scheduler layering violations in Xe (Brost)
 - Minor improvements to MERT code (Michal)
 - Privatize struct xe_ggtt_node (Maarten)
 - Convert wait for lmem init into an assert (Bala)
 - Enable GSC loading and PXP for PTL (Daniele)
 - Replace use of system_wq with tlb_inval->timeout_wq (Marco)
 - VRAM addr range bit expansion (Fei)
 - Cleanup unused header includes (Roper)

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

From: Rodrigo Vivi <rodrigo.vivi@intel.com>
Link: https://patch.msgid.link/aWkSxRQK7VhTlP32@intel.com
This commit is contained in:
Dave Airlie
2026-01-16 13:39:15 +10:00
134 changed files with 1391 additions and 973 deletions

View File

@@ -109,6 +109,22 @@ Description: RO. Package current voltage in millivolt.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp2_crit
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. Package critical temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp2_emergency
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. Package shutdown temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp2_input
Date: March 2025
KernelVersion: 6.15
@@ -117,6 +133,30 @@ Description: RO. Package temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp2_max
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. Package maximum temperature limit in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp3_crit
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. VRAM critical temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp3_emergency
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. VRAM shutdown temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp3_input
Date: March 2025
KernelVersion: 6.15
@@ -125,6 +165,76 @@ Description: RO. VRAM temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp4_crit
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. Memory controller critical temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp4_emergency
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. Memory controller shutdown temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp4_input
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. Memory controller average temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp5_crit
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. GPU PCIe critical temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp5_emergency
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. GPU PCIe shutdown temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp5_input
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. GPU PCIe temperature in millidegree Celsius.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp[6-21]_crit
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. VRAM channel critical temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp[6-21]_emergency
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. VRAM channel shutdown temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/temp[6-21]_input
Date: January 2026
KernelVersion: 7.0
Contact: intel-xe@lists.freedesktop.org
Description: RO. VRAM channel temperature in millidegree Celsius.
Only supported for particular Intel Xe graphics platforms.
What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon<i>/fan1_input
Date: March 2025
KernelVersion: 6.16

View File

@@ -480,8 +480,18 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
.start = start,
.end = end,
.pgmap_owner = pagemap->owner,
.flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT |
MIGRATE_VMA_SELECT_DEVICE_PRIVATE,
/*
* FIXME: MIGRATE_VMA_SELECT_DEVICE_PRIVATE intermittently
* causes 'xe_exec_system_allocator --r *race*no*' to trigger aa
* engine reset and a hard hang due to getting stuck on a folio
* lock. This should work and needs to be root-caused. The only
* downside of not selecting MIGRATE_VMA_SELECT_DEVICE_PRIVATE
* is that device-to-device migrations wont work; instead,
* memory will bounce through system memory. This path should be
* rare and only occur when the madvise attributes of memory are
* changed or atomics are being used.
*/
.flags = MIGRATE_VMA_SELECT_SYSTEM | MIGRATE_VMA_SELECT_DEVICE_COHERENT,
};
unsigned long i, npages = npages_in_range(start, end);
unsigned long own_pages = 0, migrated_pages = 0;
@@ -582,7 +592,7 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
err = ops->populate_devmem_pfn(devmem_allocation, npages, migrate.dst);
if (err)
goto err_finalize;
goto err_aborted_migration;
own_pages = 0;
@@ -621,8 +631,10 @@ int drm_pagemap_migrate_to_devmem(struct drm_pagemap_devmem *devmem_allocation,
err = drm_pagemap_migrate_range(devmem_allocation, migrate.src, migrate.dst,
pages, pagemap_addr, &last, &cur,
mdetails);
if (err)
if (err) {
npages = i + 1;
goto err_finalize;
}
}
cur.start = npages;
cur.ops = NULL; /* Force migration */
@@ -646,7 +658,7 @@ err_finalize:
err_aborted_migration:
migrate_vma_pages(&migrate);
for (i = 0; i < npages;) {
for (i = 0; !err && i < npages;) {
struct page *page = migrate_pfn_to_page(migrate.src[i]);
unsigned long nr_pages = page ? NR_PAGES(folio_order(page_folio(page))) : 1;

View File

@@ -370,7 +370,8 @@ always-$(CONFIG_DRM_XE_WERROR) += \
$(patsubst %.h,%.hdrtest, $(shell cd $(src) && find * -name '*.h' $(hdrtest_find_args)))
quiet_cmd_hdrtest = HDRTEST $(patsubst %.hdrtest,%.h,$@)
cmd_hdrtest = $(CC) -DHDRTEST $(filter-out $(CFLAGS_GCOV), $(c_flags)) -S -o /dev/null -x c /dev/null -include $<; touch $@
cmd_hdrtest = $(CC) $(filter-out $(CFLAGS_GCOV), $(c_flags)) -S -o /dev/null -x c /dev/null -include $< -include $<; \
$(srctree)/scripts/kernel-doc -none -Werror $<; touch $@
$(obj)/%.hdrtest: $(src)/%.h FORCE
$(call if_changed_dep,hdrtest)

View File

@@ -148,7 +148,7 @@ struct guc_lfd_data_os_info {
} __packed;
/**
* struct guc_logfile_header - Header of GuC Log Streaming-LFD-File Format.
* struct guc_lfd_file_header - Header of GuC Log Streaming-LFD-File Format.
* This structure encapsulates the layout of the guc-log-file format
*/
struct guc_lfd_file_header {
@@ -163,8 +163,7 @@ struct guc_lfd_file_header {
#define GUC_LFD_FILE_HEADER_VERSION_MASK_MAJOR GENMASK(31, 16)
#define GUC_LFD_FILE_HEADER_VERSION_MASK_MINOR GENMASK(15, 0)
/** @stream: A stream of one or more guc_lfd_data LFD blocks
*/
/** @stream: A stream of one or more guc_lfd_data LFD blocks */
u32 stream[];
} __packed;

View File

@@ -8,7 +8,7 @@
#include <uapi/drm/i915_drm.h>
#include "xe_ggtt_types.h"
#include "xe_ggtt.h"
#include <linux/refcount.h>
@@ -30,7 +30,7 @@ struct i915_vma {
static inline u32 i915_ggtt_offset(const struct i915_vma *vma)
{
return vma->node->base.start;
return xe_ggtt_node_addr(vma->node);
}
#endif

View File

@@ -171,12 +171,13 @@ static int __xe_pin_fb_vma_dpt(const struct intel_framebuffer *fb,
}
static void
write_ggtt_rotated(struct xe_bo *bo, struct xe_ggtt *ggtt, u32 *ggtt_ofs, u32 bo_ofs,
write_ggtt_rotated(struct xe_ggtt *ggtt, u32 *ggtt_ofs,
u64 pte_flags,
xe_ggtt_set_pte_fn write_pte,
struct xe_bo *bo, u32 bo_ofs,
u32 width, u32 height, u32 src_stride, u32 dst_stride)
{
struct xe_device *xe = xe_bo_device(bo);
u32 column, row;
u64 pte = ggtt->pt_ops->pte_encode_flags(bo, xe->pat.idx[XE_CACHE_NONE]);
for (column = 0; column < width; column++) {
u32 src_idx = src_stride * (height - 1) + column + bo_ofs;
@@ -184,7 +185,7 @@ write_ggtt_rotated(struct xe_bo *bo, struct xe_ggtt *ggtt, u32 *ggtt_ofs, u32 bo
for (row = 0; row < height; row++) {
u64 addr = xe_bo_addr(bo, src_idx * XE_PAGE_SIZE, XE_PAGE_SIZE);
ggtt->pt_ops->ggtt_set_pte(ggtt, *ggtt_ofs, pte | addr);
write_pte(ggtt, *ggtt_ofs, pte_flags | addr);
*ggtt_ofs += XE_PAGE_SIZE;
src_idx -= src_stride;
}
@@ -194,6 +195,28 @@ write_ggtt_rotated(struct xe_bo *bo, struct xe_ggtt *ggtt, u32 *ggtt_ofs, u32 bo
}
}
struct fb_rotate_args {
const struct i915_gtt_view *view;
struct xe_bo *bo;
};
static void write_ggtt_rotated_node(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
u64 pte_flags, xe_ggtt_set_pte_fn write_pte, void *data)
{
struct fb_rotate_args *args = data;
struct xe_bo *bo = args->bo;
const struct intel_rotation_info *rot_info = &args->view->rotated;
u32 ggtt_ofs = xe_ggtt_node_addr(node);
for (u32 i = 0; i < ARRAY_SIZE(rot_info->plane); i++)
write_ggtt_rotated(ggtt, &ggtt_ofs, pte_flags, write_pte,
bo, rot_info->plane[i].offset,
rot_info->plane[i].width,
rot_info->plane[i].height,
rot_info->plane[i].src_stride,
rot_info->plane[i].dst_stride);
}
static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb,
const struct i915_gtt_view *view,
struct i915_vma *vma,
@@ -204,66 +227,43 @@ static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb,
struct xe_device *xe = to_xe_device(fb->base.dev);
struct xe_tile *tile0 = xe_device_get_root_tile(xe);
struct xe_ggtt *ggtt = tile0->mem.ggtt;
u64 pte, size;
u32 align;
int ret;
int ret = 0;
/* TODO: Consider sharing framebuffer mapping?
* embed i915_vma inside intel_framebuffer
*/
guard(xe_pm_runtime_noresume)(xe);
ACQUIRE(mutex_intr, lock)(&ggtt->lock);
ret = ACQUIRE_ERR(mutex_intr, &lock);
if (ret)
return ret;
align = XE_PAGE_SIZE;
if (xe_bo_is_vram(bo) && ggtt->flags & XE_GGTT_FLAGS_64K)
align = max_t(u32, align, SZ_64K);
if (xe_bo_is_vram(bo) && xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K)
align = max(align, SZ_64K);
/* Fast case, preallocated GGTT view? */
if (bo->ggtt_node[tile0->id] && view->type == I915_GTT_VIEW_NORMAL) {
vma->node = bo->ggtt_node[tile0->id];
} else if (view->type == I915_GTT_VIEW_NORMAL) {
vma->node = xe_ggtt_node_init(ggtt);
if (IS_ERR(vma->node))
return PTR_ERR(vma->node);
ret = xe_ggtt_node_insert_locked(vma->node, xe_bo_size(bo), align, 0);
if (ret) {
xe_ggtt_node_fini(vma->node);
return ret;
}
xe_ggtt_map_bo(ggtt, vma->node, bo, xe->pat.idx[XE_CACHE_NONE]);
} else {
u32 i, ggtt_ofs;
const struct intel_rotation_info *rot_info = &view->rotated;
/* display seems to use tiles instead of bytes here, so convert it back.. */
u32 size = intel_rotation_info_size(rot_info) * XE_PAGE_SIZE;
vma->node = xe_ggtt_node_init(ggtt);
if (IS_ERR(vma->node)) {
ret = PTR_ERR(vma->node);
return ret;
}
ret = xe_ggtt_node_insert_locked(vma->node, size, align, 0);
if (ret) {
xe_ggtt_node_fini(vma->node);
return ret;
}
ggtt_ofs = vma->node->base.start;
for (i = 0; i < ARRAY_SIZE(rot_info->plane); i++)
write_ggtt_rotated(bo, ggtt, &ggtt_ofs,
rot_info->plane[i].offset,
rot_info->plane[i].width,
rot_info->plane[i].height,
rot_info->plane[i].src_stride,
rot_info->plane[i].dst_stride);
return 0;
}
/* TODO: Consider sharing framebuffer mapping?
* embed i915_vma inside intel_framebuffer
*/
if (view->type == I915_GTT_VIEW_NORMAL)
size = xe_bo_size(bo);
else
/* display uses tiles instead of bytes here, so convert it back.. */
size = intel_rotation_info_size(&view->rotated) * XE_PAGE_SIZE;
pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe->pat.idx[XE_CACHE_NONE]);
vma->node = xe_ggtt_node_insert_transform(ggtt, bo, pte,
ALIGN(size, align), align,
view->type == I915_GTT_VIEW_NORMAL ?
NULL : write_ggtt_rotated_node,
&(struct fb_rotate_args){view, bo});
if (IS_ERR(vma->node))
ret = PTR_ERR(vma->node);
return ret;
}
@@ -353,7 +353,7 @@ static void __xe_unpin_fb_vma(struct i915_vma *vma)
if (vma->dpt)
xe_bo_unpin_map_no_vm(vma->dpt);
else if (!xe_ggtt_node_allocated(vma->bo->ggtt_node[tile_id]) ||
vma->bo->ggtt_node[tile_id]->base.start != vma->node->base.start)
vma->bo->ggtt_node[tile_id] != vma->node)
xe_ggtt_node_remove(vma->node, false);
ttm_bo_reserve(&vma->bo->ttm, false, false, NULL);

View File

@@ -39,7 +39,7 @@ static bool intel_hdcp_gsc_check_status(struct drm_device *drm)
struct xe_gt *gt = tile->media_gt;
struct xe_gsc *gsc = &gt->uc.gsc;
if (!gsc || !xe_uc_fw_is_enabled(&gsc->fw)) {
if (!gsc || !xe_uc_fw_is_available(&gsc->fw)) {
drm_dbg_kms(&xe->drm,
"GSC Components not ready for HDCP2.x\n");
return false;

View File

@@ -78,7 +78,7 @@ static u64 xe_stolen_node_address(const struct intel_stolen_node *node)
static u64 xe_stolen_node_size(const struct intel_stolen_node *node)
{
return node->bo->ttm.base.size;
return xe_bo_size(node->bo);
}
static struct intel_stolen_node *xe_stolen_node_alloc(struct drm_device *drm)

View File

@@ -89,6 +89,7 @@
#define UNIFIED_COMPRESSION_FORMAT REG_GENMASK(3, 0)
#define XE2_GAMREQSTRM_CTRL XE_REG_MCR(0x4194)
#define EN_CMP_1WCOH REG_BIT(15)
#define CG_DIS_CNTLBUS REG_BIT(6)
#define CCS_AUX_INV XE_REG(0x4208)
@@ -101,6 +102,11 @@
#define XE2_LMEM_CFG XE_REG(0x48b0)
#define XE2_GAMWALK_CTRL 0x47e4
#define XE2_GAMWALK_CTRL_MEDIA XE_REG(XE2_GAMWALK_CTRL + MEDIA_GT_GSI_OFFSET)
#define XE2_GAMWALK_CTRL_3D XE_REG_MCR(XE2_GAMWALK_CTRL)
#define EN_CMP_1WCOH_GW REG_BIT(14)
#define XEHP_FLAT_CCS_BASE_ADDR XE_REG_MCR(0x4910)
#define XEHP_FLAT_CCS_PTR REG_GENMASK(31, 8)

View File

@@ -11,11 +11,13 @@
#define MERT_LMEM_CFG XE_REG(0x1448b0)
#define MERT_TLB_CT_INTR_ERR_ID_PORT XE_REG(0x145190)
#define MERT_TLB_CT_VFID_MASK REG_GENMASK(16, 9)
#define MERT_TLB_CT_ERROR_MASK REG_GENMASK(5, 0)
#define MERT_TLB_CT_LMTT_FAULT 0x05
#define CATERR_VFID REG_GENMASK(16, 9)
#define CATERR_CODES REG_GENMASK(5, 0)
#define CATERR_NO_ERROR 0x00
#define CATERR_UNMAPPED_GGTT 0x01
#define CATERR_LMTT_FAULT 0x05
#define MERT_TLB_INV_DESC_A XE_REG(0x14cf7c)
#define MERT_TLB_INV_DESC_A_VALID REG_BIT(0)
#endif /* _XE_MERT_REGS_H_ */
#endif

View File

@@ -21,7 +21,10 @@
#define BMG_FAN_1_SPEED XE_REG(0x138140)
#define BMG_FAN_2_SPEED XE_REG(0x138170)
#define BMG_FAN_3_SPEED XE_REG(0x1381a0)
#define BMG_VRAM_TEMPERATURE_N(n) XE_REG(0x138260 + ((n) * (sizeof(u32))))
#define BMG_VRAM_TEMPERATURE XE_REG(0x1382c0)
#define TEMP_MASK_VRAM_N REG_GENMASK(30, 8)
#define TEMP_SIGN_MASK REG_BIT(31)
#define BMG_PACKAGE_TEMPERATURE XE_REG(0x138434)
#endif /* _XE_PCODE_REGS_H_ */

View File

@@ -18,6 +18,7 @@
#include "tests/xe_test.h"
#include "xe_bo_evict.h"
#include "xe_gt.h"
#include "xe_pci.h"
#include "xe_pm.h"

View File

@@ -67,7 +67,7 @@ static int guc_buf_test_init(struct kunit *test)
KUNIT_ASSERT_EQ(test, 0,
xe_ggtt_init_kunit(ggtt, DUT_GGTT_START,
DUT_GGTT_START + DUT_GGTT_SIZE));
DUT_GGTT_SIZE));
kunit_activate_static_stub(test, xe_managed_bo_create_pin_map,
replacement_xe_managed_bo_create_pin_map);

View File

@@ -7,10 +7,9 @@
#include "instructions/xe_mi_commands.h"
#include "xe_assert.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_exec_queue_types.h"
#include "xe_gt.h"
#include "xe_hw_fence.h"
#include "xe_sa.h"
#include "xe_sched_job.h"
#include "xe_vm_types.h"

View File

@@ -26,9 +26,9 @@
#include "xe_dma_buf.h"
#include "xe_drm_client.h"
#include "xe_ggtt.h"
#include "xe_gt.h"
#include "xe_map.h"
#include "xe_migrate.h"
#include "xe_pat.h"
#include "xe_pm.h"
#include "xe_preempt_fence.h"
#include "xe_pxp.h"
@@ -1054,6 +1054,7 @@ static long xe_bo_shrink_purge(struct ttm_operation_ctx *ctx,
unsigned long *scanned)
{
struct xe_device *xe = ttm_to_xe_device(bo->bdev);
struct ttm_tt *tt = bo->ttm;
long lret;
/* Fake move to system, without copying data. */
@@ -1078,8 +1079,10 @@ static long xe_bo_shrink_purge(struct ttm_operation_ctx *ctx,
.writeback = false,
.allow_move = false});
if (lret > 0)
if (lret > 0) {
xe_ttm_tt_account_subtract(xe, bo->ttm);
update_global_total_pages(bo->bdev, -(long)tt->num_pages);
}
return lret;
}
@@ -1165,8 +1168,10 @@ long xe_bo_shrink(struct ttm_operation_ctx *ctx, struct ttm_buffer_object *bo,
if (needs_rpm)
xe_pm_runtime_put(xe);
if (lret > 0)
if (lret > 0) {
xe_ttm_tt_account_subtract(xe, tt);
update_global_total_pages(bo->bdev, -(long)tt->num_pages);
}
out_unref:
xe_bo_put(xe_bo);
@@ -1709,7 +1714,7 @@ static void xe_ttm_bo_destroy(struct ttm_buffer_object *ttm_bo)
xe_assert(xe, list_empty(&ttm_bo->base.gpuva.list));
for_each_tile(tile, xe, id)
if (bo->ggtt_node[id] && bo->ggtt_node[id]->base.size)
if (bo->ggtt_node[id])
xe_ggtt_remove_bo(tile->mem.ggtt, bo);
#ifdef CONFIG_PROC_FS
@@ -3517,16 +3522,16 @@ bool xe_bo_needs_ccs_pages(struct xe_bo *bo)
if (IS_DGFX(xe) && (bo->flags & XE_BO_FLAG_SYSTEM))
return false;
/* Check if userspace explicitly requested no compression */
if (bo->flags & XE_BO_FLAG_NO_COMPRESSION)
return false;
/*
* Compression implies coh_none, therefore we know for sure that WB
* memory can't currently use compression, which is likely one of the
* common cases.
* Additionally, userspace may explicitly request no compression via the
* DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION flag, which should also disable
* CCS usage.
* For WB (Write-Back) CPU caching mode, check if the device
* supports WB compression with coherency.
*/
if (bo->cpu_caching == DRM_XE_GEM_CPU_CACHING_WB ||
bo->flags & XE_BO_FLAG_NO_COMPRESSION)
if (bo->cpu_caching == DRM_XE_GEM_CPU_CACHING_WB &&
xe->pat.idx[XE_CACHE_WB_COMPRESSION] == XE_PAT_INVALID_IDX)
return false;
return true;
@@ -3603,8 +3608,8 @@ void xe_bo_put(struct xe_bo *bo)
might_lock(&bo->client->bos_lock);
#endif
for_each_tile(tile, xe_bo_device(bo), id)
if (bo->ggtt_node[id] && bo->ggtt_node[id]->ggtt)
xe_ggtt_might_lock(bo->ggtt_node[id]->ggtt);
if (bo->ggtt_node[id])
xe_ggtt_might_lock(tile->mem.ggtt);
drm_gem_object_put(&bo->ttm.base);
}
}

View File

@@ -9,6 +9,7 @@
#include <drm/ttm/ttm_tt.h>
#include "xe_bo_types.h"
#include "xe_ggtt.h"
#include "xe_macros.h"
#include "xe_validation.h"
#include "xe_vm_types.h"
@@ -252,13 +253,14 @@ static inline u32
__xe_bo_ggtt_addr(struct xe_bo *bo, u8 tile_id)
{
struct xe_ggtt_node *ggtt_node = bo->ggtt_node[tile_id];
u64 offset;
if (XE_WARN_ON(!ggtt_node))
return 0;
XE_WARN_ON(ggtt_node->base.size > xe_bo_size(bo));
XE_WARN_ON(ggtt_node->base.start + ggtt_node->base.size > (1ull << 32));
return ggtt_node->base.start;
offset = xe_ggtt_node_addr(ggtt_node);
XE_WARN_ON(offset + xe_bo_size(bo) > (1ull << 32));
return offset;
}
static inline u32

View File

@@ -254,36 +254,81 @@ static ssize_t wedged_mode_show(struct file *f, char __user *ubuf,
return simple_read_from_buffer(ubuf, size, pos, buf, len);
}
static int __wedged_mode_set_reset_policy(struct xe_gt *gt, enum xe_wedged_mode mode)
{
bool enable_engine_reset;
int ret;
enable_engine_reset = (mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET);
ret = xe_guc_ads_scheduler_policy_toggle_reset(&gt->uc.guc.ads,
enable_engine_reset);
if (ret)
xe_gt_err(gt, "Failed to update GuC ADS scheduler policy (%pe)\n", ERR_PTR(ret));
return ret;
}
static int wedged_mode_set_reset_policy(struct xe_device *xe, enum xe_wedged_mode mode)
{
struct xe_gt *gt;
int ret;
u8 id;
guard(xe_pm_runtime)(xe);
for_each_gt(gt, xe, id) {
ret = __wedged_mode_set_reset_policy(gt, mode);
if (ret) {
if (id > 0) {
xe->wedged.inconsistent_reset = true;
drm_err(&xe->drm, "Inconsistent reset policy state between GTs\n");
}
return ret;
}
}
xe->wedged.inconsistent_reset = false;
return 0;
}
static bool wedged_mode_needs_policy_update(struct xe_device *xe, enum xe_wedged_mode mode)
{
if (xe->wedged.inconsistent_reset)
return true;
if (xe->wedged.mode == mode)
return false;
if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET ||
mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
return true;
return false;
}
static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf,
size_t size, loff_t *pos)
{
struct xe_device *xe = file_inode(f)->i_private;
struct xe_gt *gt;
u32 wedged_mode;
ssize_t ret;
u8 id;
ret = kstrtouint_from_user(ubuf, size, 0, &wedged_mode);
if (ret)
return ret;
if (wedged_mode > 2)
return -EINVAL;
ret = xe_device_validate_wedged_mode(xe, wedged_mode);
if (ret)
return ret;
if (xe->wedged.mode == wedged_mode)
return size;
if (wedged_mode_needs_policy_update(xe, wedged_mode)) {
ret = wedged_mode_set_reset_policy(xe, wedged_mode);
if (ret)
return ret;
}
xe->wedged.mode = wedged_mode;
guard(xe_pm_runtime)(xe);
for_each_gt(gt, xe, id) {
ret = xe_guc_ads_scheduler_policy_toggle_reset(&gt->uc.guc.ads);
if (ret) {
xe_gt_err(gt, "Failed to update GuC ADS scheduler policy. GuC may still cause engine reset even with wedged_mode=2\n");
return -EIO;
}
}
return size;
}

View File

@@ -15,14 +15,13 @@
#include "xe_device.h"
#include "xe_exec_queue.h"
#include "xe_force_wake.h"
#include "xe_gt.h"
#include "xe_gt_printk.h"
#include "xe_gt_types.h"
#include "xe_guc_capture.h"
#include "xe_guc_ct.h"
#include "xe_guc_log.h"
#include "xe_guc_submit.h"
#include "xe_hw_engine.h"
#include "xe_module.h"
#include "xe_pm.h"
#include "xe_sched_job.h"
#include "xe_vm.h"

View File

@@ -8,7 +8,6 @@
#include <linux/aperture.h>
#include <linux/delay.h>
#include <linux/fault-inject.h>
#include <linux/iopoll.h>
#include <linux/units.h>
#include <drm/drm_atomic_helper.h>
@@ -36,7 +35,6 @@
#include "xe_exec_queue.h"
#include "xe_force_wake.h"
#include "xe_ggtt.h"
#include "xe_gsc_proxy.h"
#include "xe_gt.h"
#include "xe_gt_mcr.h"
#include "xe_gt_printk.h"
@@ -180,12 +178,7 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file)
xa_for_each(&xef->exec_queue.xa, idx, q) {
if (q->vm && q->hwe->hw_engine_group)
xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q);
if (xe_exec_queue_is_multi_queue_primary(q))
xe_exec_queue_group_kill_put(q->multi_queue.group);
else
xe_exec_queue_kill(q);
xe_exec_queue_kill(q);
xe_exec_queue_put(q);
}
xa_for_each(&xef->vm.xa, idx, vm)
@@ -659,63 +652,15 @@ mask_err:
return err;
}
static int lmem_initializing(struct xe_device *xe)
static void assert_lmem_ready(struct xe_device *xe)
{
if (xe_mmio_read32(xe_root_tile_mmio(xe), GU_CNTL) & LMEM_INIT)
return 0;
if (!IS_DGFX(xe) || IS_SRIOV_VF(xe))
return;
if (signal_pending(current))
return -EINTR;
return 1;
xe_assert(xe, xe_mmio_read32(xe_root_tile_mmio(xe), GU_CNTL) &
LMEM_INIT);
}
static int wait_for_lmem_ready(struct xe_device *xe)
{
const unsigned long TIMEOUT_SEC = 60;
unsigned long prev_jiffies;
int initializing;
if (!IS_DGFX(xe))
return 0;
if (IS_SRIOV_VF(xe))
return 0;
if (!lmem_initializing(xe))
return 0;
drm_dbg(&xe->drm, "Waiting for lmem initialization\n");
prev_jiffies = jiffies;
/*
* The boot firmware initializes local memory and
* assesses its health. If memory training fails,
* the punit will have been instructed to keep the GT powered
* down.we won't be able to communicate with it
*
* If the status check is done before punit updates the register,
* it can lead to the system being unusable.
* use a timeout and defer the probe to prevent this.
*/
poll_timeout_us(initializing = lmem_initializing(xe),
initializing <= 0,
20 * USEC_PER_MSEC, TIMEOUT_SEC * USEC_PER_SEC, true);
if (initializing < 0)
return initializing;
if (initializing) {
drm_dbg(&xe->drm, "lmem not initialized by firmware\n");
return -EPROBE_DEFER;
}
drm_dbg(&xe->drm, "lmem ready after %ums",
jiffies_to_msecs(jiffies - prev_jiffies));
return 0;
}
ALLOW_ERROR_INJECTION(wait_for_lmem_ready, ERRNO); /* See xe_pci_probe() */
static void vf_update_device_info(struct xe_device *xe)
{
xe_assert(xe, IS_SRIOV_VF(xe));
@@ -769,6 +714,11 @@ int xe_device_probe_early(struct xe_device *xe)
if (IS_SRIOV_VF(xe))
vf_update_device_info(xe);
/*
* Check for pcode uncore_init status to confirm if the SoC
* initialization is complete. Until done, any MMIO or lmem access from
* the driver will be blocked
*/
err = xe_pcode_probe_early(xe);
if (err || xe_survivability_mode_is_requested(xe)) {
int save_err = err;
@@ -785,11 +735,17 @@ int xe_device_probe_early(struct xe_device *xe)
return save_err;
}
err = wait_for_lmem_ready(xe);
if (err)
return err;
/*
* Make sure the lmem is initialized and ready to use. xe_pcode_ready()
* is flagged after full initialization is complete. Assert if lmem is
* not initialized.
*/
assert_lmem_ready(xe);
xe->wedged.mode = xe_modparam.wedged_mode;
xe->wedged.mode = xe_device_validate_wedged_mode(xe, xe_modparam.wedged_mode) ?
XE_WEDGED_MODE_DEFAULT : xe_modparam.wedged_mode;
drm_dbg(&xe->drm, "wedged_mode: setting mode (%u) %s\n",
xe->wedged.mode, xe_wedged_mode_to_string(xe->wedged.mode));
err = xe_device_vram_alloc(xe);
if (err)
@@ -1272,10 +1228,10 @@ static void xe_device_wedged_fini(struct drm_device *drm, void *arg)
* DOC: Xe Device Wedging
*
* Xe driver uses drm device wedged uevent as documented in Documentation/gpu/drm-uapi.rst.
* When device is in wedged state, every IOCTL will be blocked and GT cannot be
* used. Certain critical errors like gt reset failure, firmware failures can cause
* the device to be wedged. The default recovery method for a wedged state
* is rebind/bus-reset.
* When device is in wedged state, every IOCTL will be blocked and GT cannot
* be used. The conditions under which the driver declares the device wedged
* depend on the wedged mode configuration (see &enum xe_wedged_mode). The
* default recovery method for a wedged state is rebind/bus-reset.
*
* Another recovery method is vendor-specific. Below are the cases that send
* ``WEDGED=vendor-specific`` recovery method in drm device wedged uevent.
@@ -1340,7 +1296,7 @@ void xe_device_declare_wedged(struct xe_device *xe)
struct xe_gt *gt;
u8 id;
if (xe->wedged.mode == 0) {
if (xe->wedged.mode == XE_WEDGED_MODE_NEVER) {
drm_dbg(&xe->drm, "Wedged mode is forcibly disabled\n");
return;
}
@@ -1374,3 +1330,48 @@ void xe_device_declare_wedged(struct xe_device *xe)
drm_dev_wedged_event(&xe->drm, xe->wedged.method, NULL);
}
}
/**
* xe_device_validate_wedged_mode - Check if given mode is supported
* @xe: the &xe_device
* @mode: requested mode to validate
*
* Check whether the provided wedged mode is supported.
*
* Return: 0 if mode is supported, error code otherwise.
*/
int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode)
{
if (mode > XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET) {
drm_dbg(&xe->drm, "wedged_mode: invalid value (%u)\n", mode);
return -EINVAL;
} else if (mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET && (IS_SRIOV_VF(xe) ||
(IS_SRIOV_PF(xe) && !IS_ENABLED(CONFIG_DRM_XE_DEBUG)))) {
drm_dbg(&xe->drm, "wedged_mode: (%u) %s mode is not supported for %s\n",
mode, xe_wedged_mode_to_string(mode),
xe_sriov_mode_to_string(xe_device_sriov_mode(xe)));
return -EPERM;
}
return 0;
}
/**
* xe_wedged_mode_to_string - Convert enum value to string.
* @mode: the &xe_wedged_mode to convert
*
* Returns: wedged mode as a user friendly string.
*/
const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode)
{
switch (mode) {
case XE_WEDGED_MODE_NEVER:
return "never";
case XE_WEDGED_MODE_UPON_CRITICAL_ERROR:
return "upon-critical-error";
case XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET:
return "upon-any-hang-no-reset";
default:
return "<invalid>";
}
}

View File

@@ -194,6 +194,8 @@ static inline bool xe_device_wedged(struct xe_device *xe)
void xe_device_set_wedged_method(struct xe_device *xe, unsigned long method);
void xe_device_declare_wedged(struct xe_device *xe);
int xe_device_validate_wedged_mode(struct xe_device *xe, unsigned int mode);
const char *xe_wedged_mode_to_string(enum xe_wedged_mode mode);
struct xe_file *xe_file_get(struct xe_file *xef);
void xe_file_put(struct xe_file *xef);

View File

@@ -46,6 +46,25 @@ struct xe_pat_ops;
struct xe_pxp;
struct xe_vram_region;
/**
* enum xe_wedged_mode - possible wedged modes
* @XE_WEDGED_MODE_NEVER: Device will never be declared wedged.
* @XE_WEDGED_MODE_UPON_CRITICAL_ERROR: Device will be declared wedged only
* when critical error occurs like GT reset failure or firmware failure.
* This is the default mode.
* @XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET: Device will be declared wedged on
* any hang. In this mode, engine resets are disabled to avoid automatic
* recovery attempts. This mode is primarily intended for debugging hangs.
*/
enum xe_wedged_mode {
XE_WEDGED_MODE_NEVER = 0,
XE_WEDGED_MODE_UPON_CRITICAL_ERROR = 1,
XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET = 2,
};
#define XE_WEDGED_MODE_DEFAULT XE_WEDGED_MODE_UPON_CRITICAL_ERROR
#define XE_WEDGED_MODE_DEFAULT_STR "upon-critical-error"
#define XE_BO_INVALID_OFFSET LONG_MAX
#define GRAPHICS_VER(xe) ((xe)->info.graphics_verx100 / 100)
@@ -322,6 +341,8 @@ struct xe_device {
* pcode mailbox commands.
*/
u8 has_mbx_power_limits:1;
/** @info.has_mbx_thermal_info: Device supports thermal mailbox commands */
u8 has_mbx_thermal_info:1;
/** @info.has_mem_copy_instr: Device supports MEM_COPY instruction */
u8 has_mem_copy_instr:1;
/** @info.has_mert: Device has standalone MERT */
@@ -626,9 +647,11 @@ struct xe_device {
/** @wedged.flag: Xe device faced a critical error and is now blocked. */
atomic_t flag;
/** @wedged.mode: Mode controlled by kernel parameter and debugfs */
int mode;
enum xe_wedged_mode mode;
/** @wedged.method: Recovery method to be sent in the drm device wedged uevent */
unsigned long method;
/** @wedged.inconsistent_reset: Inconsistent reset policy state between GTs */
bool inconsistent_reset;
} wedged;
/** @bo_device: Struct to control async free of BOs */

View File

@@ -11,7 +11,6 @@
#include <uapi/drm/xe_drm.h>
#include <linux/delay.h>
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_exec_queue.h"
#include "xe_hw_engine_group.h"

View File

@@ -21,13 +21,11 @@
#include "xe_gt_sriov_vf.h"
#include "xe_hw_engine_class_sysfs.h"
#include "xe_hw_engine_group.h"
#include "xe_hw_fence.h"
#include "xe_irq.h"
#include "xe_lrc.h"
#include "xe_macros.h"
#include "xe_migrate.h"
#include "xe_pm.h"
#include "xe_ring_ops_types.h"
#include "xe_trace.h"
#include "xe_vm.h"
#include "xe_pxp.h"
@@ -84,9 +82,8 @@
* group is destroyed. The secondary queues hold a reference to the primary
* queue thus preventing the group from being destroyed when user destroys
* the primary queue. Once the primary queue is destroyed, secondary queues
* can't be added to the queue group, but they can continue to submit the
* jobs if the DRM_XE_MULTI_GROUP_KEEP_ACTIVE flag is set during the multi
* queue group creation.
* can't be added to the queue group and new job submissions on existing
* secondary queues are not allowed.
*
* The queues of a multi queue group can set their priority within the group
* through the DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY property.
@@ -467,26 +464,6 @@ struct xe_exec_queue *xe_exec_queue_create_bind(struct xe_device *xe,
}
ALLOW_ERROR_INJECTION(xe_exec_queue_create_bind, ERRNO);
static void xe_exec_queue_group_kill(struct kref *ref)
{
struct xe_exec_queue_group *group = container_of(ref, struct xe_exec_queue_group,
kill_refcount);
xe_exec_queue_kill(group->primary);
}
static inline void xe_exec_queue_group_kill_get(struct xe_exec_queue_group *group)
{
kref_get(&group->kill_refcount);
}
void xe_exec_queue_group_kill_put(struct xe_exec_queue_group *group)
{
if (!group)
return;
kref_put(&group->kill_refcount, xe_exec_queue_group_kill);
}
void xe_exec_queue_destroy(struct kref *ref)
{
struct xe_exec_queue *q = container_of(ref, struct xe_exec_queue, refcount);
@@ -716,7 +693,6 @@ static int xe_exec_queue_group_init(struct xe_device *xe, struct xe_exec_queue *
group->primary = q;
group->cgp_bo = bo;
INIT_LIST_HEAD(&group->list);
kref_init(&group->kill_refcount);
xa_init_flags(&group->xa, XA_FLAGS_ALLOC1);
mutex_init(&group->list_lock);
q->multi_queue.group = group;
@@ -792,11 +768,6 @@ static int xe_exec_queue_group_add(struct xe_device *xe, struct xe_exec_queue *q
q->multi_queue.pos = pos;
if (group->primary->multi_queue.keep_active) {
xe_exec_queue_group_kill_get(group);
q->multi_queue.keep_active = true;
}
return 0;
}
@@ -810,11 +781,6 @@ static void xe_exec_queue_group_delete(struct xe_device *xe, struct xe_exec_queu
lrc = xa_erase(&group->xa, q->multi_queue.pos);
xe_assert(xe, lrc);
xe_lrc_put(lrc);
if (q->multi_queue.keep_active) {
xe_exec_queue_group_kill_put(group);
q->multi_queue.keep_active = false;
}
}
static int exec_queue_set_multi_group(struct xe_device *xe, struct xe_exec_queue *q,
@@ -836,24 +802,12 @@ static int exec_queue_set_multi_group(struct xe_device *xe, struct xe_exec_queue
return -EINVAL;
if (value & DRM_XE_MULTI_GROUP_CREATE) {
if (XE_IOCTL_DBG(xe, value & ~(DRM_XE_MULTI_GROUP_CREATE |
DRM_XE_MULTI_GROUP_KEEP_ACTIVE)))
return -EINVAL;
/*
* KEEP_ACTIVE is not supported in preempt fence mode as in that mode,
* VM_DESTROY ioctl expects all exec queues of that VM are already killed.
*/
if (XE_IOCTL_DBG(xe, (value & DRM_XE_MULTI_GROUP_KEEP_ACTIVE) &&
xe_vm_in_preempt_fence_mode(q->vm)))
if (XE_IOCTL_DBG(xe, value & ~DRM_XE_MULTI_GROUP_CREATE))
return -EINVAL;
q->multi_queue.valid = true;
q->multi_queue.is_primary = true;
q->multi_queue.pos = 0;
if (value & DRM_XE_MULTI_GROUP_KEEP_ACTIVE)
q->multi_queue.keep_active = true;
return 0;
}
@@ -1419,11 +1373,6 @@ void xe_exec_queue_kill(struct xe_exec_queue *q)
q->ops->kill(q);
xe_vm_remove_compute_exec_queue(q->vm, q);
if (!xe_exec_queue_is_multi_queue_primary(q) && q->multi_queue.keep_active) {
xe_exec_queue_group_kill_put(q->multi_queue.group);
q->multi_queue.keep_active = false;
}
}
int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data,
@@ -1450,10 +1399,7 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data,
if (q->vm && q->hwe->hw_engine_group)
xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q);
if (xe_exec_queue_is_multi_queue_primary(q))
xe_exec_queue_group_kill_put(q->multi_queue.group);
else
xe_exec_queue_kill(q);
xe_exec_queue_kill(q);
trace_xe_exec_queue_close(q);
xe_exec_queue_put(q);

View File

@@ -113,8 +113,6 @@ static inline struct xe_exec_queue *xe_exec_queue_multi_queue_primary(struct xe_
return xe_exec_queue_is_multi_queue(q) ? q->multi_queue.group->primary : q;
}
void xe_exec_queue_group_kill_put(struct xe_exec_queue_group *group);
bool xe_exec_queue_is_lr(struct xe_exec_queue *q);
bool xe_exec_queue_is_idle(struct xe_exec_queue *q);

View File

@@ -62,8 +62,6 @@ struct xe_exec_queue_group {
struct list_head list;
/** @list_lock: Secondary queue list lock */
struct mutex list_lock;
/** @kill_refcount: ref count to kill primary queue */
struct kref kill_refcount;
/** @sync_pending: CGP_SYNC_DONE g2h response pending */
bool sync_pending;
/** @banned: Group banned */
@@ -163,8 +161,6 @@ struct xe_exec_queue {
u8 valid:1;
/** @multi_queue.is_primary: Is primary queue (Q0) of the group */
u8 is_primary:1;
/** @multi_queue.keep_active: Keep the group active after primary is destroyed */
u8 keep_active:1;
} multi_queue;
/** @sched_props: scheduling properties */

View File

@@ -15,8 +15,7 @@
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_exec_queue.h"
#include "xe_gt.h"
#include "xe_hw_fence.h"
#include "xe_gt_types.h"
#include "xe_irq.h"
#include "xe_lrc.h"
#include "xe_macros.h"

View File

@@ -20,9 +20,8 @@
#include "regs/xe_regs.h"
#include "xe_assert.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_gt_printk.h"
#include "xe_gt_types.h"
#include "xe_map.h"
#include "xe_mmio.h"
#include "xe_pm.h"
@@ -67,6 +66,24 @@
* give us the correct placement for free.
*/
/**
* struct xe_ggtt_node - A node in GGTT.
*
* This struct needs to be initialized (only-once) with xe_ggtt_node_init() before any node
* insertion, reservation, or 'ballooning'.
* It will, then, be finalized by either xe_ggtt_node_remove() or xe_ggtt_node_deballoon().
*/
struct xe_ggtt_node {
/** @ggtt: Back pointer to xe_ggtt where this region will be inserted at */
struct xe_ggtt *ggtt;
/** @base: A drm_mm_node */
struct drm_mm_node base;
/** @delayed_removal_work: The work struct for the delayed removal */
struct work_struct delayed_removal_work;
/** @invalidate_on_remove: If it needs invalidation upon removal */
bool invalidate_on_remove;
};
static u64 xelp_ggtt_pte_flags(struct xe_bo *bo, u16 pat_index)
{
u64 pte = XE_PAGE_PRESENT;
@@ -137,10 +154,32 @@ static void ggtt_update_access_counter(struct xe_ggtt *ggtt)
}
}
/**
* xe_ggtt_start - Get starting offset of GGTT.
* @ggtt: &xe_ggtt
*
* Returns: Starting offset for this &xe_ggtt.
*/
u64 xe_ggtt_start(struct xe_ggtt *ggtt)
{
return ggtt->start;
}
/**
* xe_ggtt_size - Get size of GGTT.
* @ggtt: &xe_ggtt
*
* Returns: Total usable size of this &xe_ggtt.
*/
u64 xe_ggtt_size(struct xe_ggtt *ggtt)
{
return ggtt->size;
}
static void xe_ggtt_set_pte(struct xe_ggtt *ggtt, u64 addr, u64 pte)
{
xe_tile_assert(ggtt->tile, !(addr & XE_PTE_MASK));
xe_tile_assert(ggtt->tile, addr < ggtt->size);
xe_tile_assert(ggtt->tile, addr < ggtt->start + ggtt->size);
writeq(pte, &ggtt->gsm[addr >> XE_PTE_SHIFT]);
}
@@ -256,16 +295,16 @@ static const struct xe_ggtt_pt_ops xelpg_pt_wa_ops = {
.ggtt_get_pte = xe_ggtt_get_pte,
};
static void __xe_ggtt_init_early(struct xe_ggtt *ggtt, u32 reserved)
static void __xe_ggtt_init_early(struct xe_ggtt *ggtt, u64 start, u64 size)
{
drm_mm_init(&ggtt->mm, reserved,
ggtt->size - reserved);
ggtt->start = start;
ggtt->size = size;
drm_mm_init(&ggtt->mm, start, size);
}
int xe_ggtt_init_kunit(struct xe_ggtt *ggtt, u32 reserved, u32 size)
int xe_ggtt_init_kunit(struct xe_ggtt *ggtt, u32 start, u32 size)
{
ggtt->size = size;
__xe_ggtt_init_early(ggtt, reserved);
__xe_ggtt_init_early(ggtt, start, size);
return 0;
}
EXPORT_SYMBOL_IF_KUNIT(xe_ggtt_init_kunit);
@@ -293,26 +332,32 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
struct xe_device *xe = tile_to_xe(ggtt->tile);
struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
unsigned int gsm_size;
u64 ggtt_start, wopcm = xe_wopcm_size(xe), ggtt_size;
int err;
if (IS_SRIOV_VF(xe) || GRAPHICS_VERx100(xe) >= 1250)
gsm_size = SZ_8M; /* GGTT is expected to be 4GiB */
else
gsm_size = probe_gsm_size(pdev);
if (gsm_size == 0) {
xe_tile_err(ggtt->tile, "Hardware reported no preallocated GSM\n");
return -ENOMEM;
if (!IS_SRIOV_VF(xe)) {
if (GRAPHICS_VERx100(xe) >= 1250)
gsm_size = SZ_8M; /* GGTT is expected to be 4GiB */
else
gsm_size = probe_gsm_size(pdev);
if (gsm_size == 0) {
xe_tile_err(ggtt->tile, "Hardware reported no preallocated GSM\n");
return -ENOMEM;
}
ggtt_start = wopcm;
ggtt_size = (gsm_size / 8) * (u64)XE_PAGE_SIZE - ggtt_start;
} else {
/* GGTT is expected to be 4GiB */
ggtt_start = wopcm;
ggtt_size = SZ_4G - ggtt_start;
}
ggtt->gsm = ggtt->tile->mmio.regs + SZ_8M;
ggtt->size = (gsm_size / 8) * (u64) XE_PAGE_SIZE;
if (IS_DGFX(xe) && xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K)
ggtt->flags |= XE_GGTT_FLAGS_64K;
if (ggtt->size > GUC_GGTT_TOP)
ggtt->size = GUC_GGTT_TOP;
if (ggtt_size + ggtt_start > GUC_GGTT_TOP)
ggtt_size = GUC_GGTT_TOP - ggtt_start;
if (GRAPHICS_VERx100(xe) >= 1270)
ggtt->pt_ops =
@@ -322,11 +367,11 @@ int xe_ggtt_init_early(struct xe_ggtt *ggtt)
else
ggtt->pt_ops = &xelp_pt_ops;
ggtt->wq = alloc_workqueue("xe-ggtt-wq", 0, WQ_MEM_RECLAIM);
ggtt->wq = alloc_workqueue("xe-ggtt-wq", WQ_MEM_RECLAIM, 0);
if (!ggtt->wq)
return -ENOMEM;
__xe_ggtt_init_early(ggtt, xe_wopcm_size(xe));
__xe_ggtt_init_early(ggtt, ggtt_start, ggtt_size);
err = drmm_add_action_or_reset(&xe->drm, ggtt_fini_early, ggtt);
if (err)
@@ -563,11 +608,9 @@ void xe_ggtt_node_remove_balloon_locked(struct xe_ggtt_node *node)
static void xe_ggtt_assert_fit(struct xe_ggtt *ggtt, u64 start, u64 size)
{
struct xe_tile *tile = ggtt->tile;
struct xe_device *xe = tile_to_xe(tile);
u64 __maybe_unused wopcm = xe_wopcm_size(xe);
xe_tile_assert(tile, start >= wopcm);
xe_tile_assert(tile, start + size < ggtt->size - wopcm);
xe_tile_assert(tile, start >= ggtt->start);
xe_tile_assert(tile, start + size <= ggtt->start + ggtt->size);
}
/**
@@ -610,20 +653,8 @@ void xe_ggtt_shift_nodes_locked(struct xe_ggtt *ggtt, s64 shift)
}
}
/**
* xe_ggtt_node_insert_locked - Locked version to insert a &xe_ggtt_node into the GGTT
* @node: the &xe_ggtt_node to be inserted
* @size: size of the node
* @align: alignment constrain of the node
* @mm_flags: flags to control the node behavior
*
* It cannot be called without first having called xe_ggtt_init() once.
* To be used in cases where ggtt->lock is already taken.
*
* Return: 0 on success or a negative error code on failure.
*/
int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node,
u32 size, u32 align, u32 mm_flags)
static int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node,
u32 size, u32 align, u32 mm_flags)
{
return drm_mm_insert_node_generic(&node->ggtt->mm, &node->base, size, align, 0,
mm_flags);
@@ -661,9 +692,11 @@ int xe_ggtt_node_insert(struct xe_ggtt_node *node, u32 size, u32 align)
* This function will allocate the struct %xe_ggtt_node and return its pointer.
* This struct will then be freed after the node removal upon xe_ggtt_node_remove()
* or xe_ggtt_node_remove_balloon_locked().
* Having %xe_ggtt_node struct allocated doesn't mean that the node is already allocated
* in GGTT. Only the xe_ggtt_node_insert(), xe_ggtt_node_insert_locked(),
* xe_ggtt_node_insert_balloon_locked() will ensure the node is inserted or reserved in GGTT.
*
* Having %xe_ggtt_node struct allocated doesn't mean that the node is already
* allocated in GGTT. Only xe_ggtt_node_insert(), allocation through
* xe_ggtt_node_insert_transform(), or xe_ggtt_node_insert_balloon_locked() will ensure the node is inserted or reserved
* in GGTT.
*
* Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise.
**/
@@ -726,13 +759,12 @@ size_t xe_ggtt_node_pt_size(const struct xe_ggtt_node *node)
* @ggtt: the &xe_ggtt where node will be mapped
* @node: the &xe_ggtt_node where this BO is mapped
* @bo: the &xe_bo to be mapped
* @pat_index: Which pat_index to use.
* @pte: The pte flags to append.
*/
void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
struct xe_bo *bo, u16 pat_index)
static void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
struct xe_bo *bo, u64 pte)
{
u64 start, pte, end;
u64 start, end;
struct xe_res_cursor cur;
if (XE_WARN_ON(!node))
@@ -741,7 +773,6 @@ void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
start = node->base.start;
end = start + xe_bo_size(bo);
pte = ggtt->pt_ops->pte_encode_flags(bo, pat_index);
if (!xe_bo_is_vram(bo) && !xe_bo_is_stolen(bo)) {
xe_assert(xe_bo_device(bo), bo->ttm.ttm);
@@ -771,12 +802,65 @@ void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo)
{
u16 cache_mode = bo->flags & XE_BO_FLAG_NEEDS_UC ? XE_CACHE_NONE : XE_CACHE_WB;
u16 pat_index = tile_to_xe(ggtt->tile)->pat.idx[cache_mode];
u64 pte;
mutex_lock(&ggtt->lock);
xe_ggtt_map_bo(ggtt, bo->ggtt_node[ggtt->tile->id], bo, pat_index);
pte = ggtt->pt_ops->pte_encode_flags(bo, pat_index);
xe_ggtt_map_bo(ggtt, bo->ggtt_node[ggtt->tile->id], bo, pte);
mutex_unlock(&ggtt->lock);
}
/**
* xe_ggtt_node_insert_transform - Insert a newly allocated &xe_ggtt_node into the GGTT
* @ggtt: the &xe_ggtt where the node will inserted/reserved.
* @bo: The bo to be transformed
* @pte_flags: The extra GGTT flags to add to mapping.
* @size: size of the node
* @align: required alignment for node
* @transform: transformation function that will populate the GGTT node, or NULL for linear mapping.
* @arg: Extra argument to pass to the transformation function.
*
* This function allows inserting a GGTT node with a custom transformation function.
* This is useful for display to allow inserting rotated framebuffers to GGTT.
*
* Return: A pointer to %xe_ggtt_node struct on success. An ERR_PTR otherwise.
*/
struct xe_ggtt_node *xe_ggtt_node_insert_transform(struct xe_ggtt *ggtt,
struct xe_bo *bo, u64 pte_flags,
u64 size, u32 align,
xe_ggtt_transform_cb transform, void *arg)
{
struct xe_ggtt_node *node;
int ret;
node = xe_ggtt_node_init(ggtt);
if (IS_ERR(node))
return ERR_CAST(node);
if (mutex_lock_interruptible(&ggtt->lock) < 0) {
ret = -ERESTARTSYS;
goto err;
}
ret = xe_ggtt_node_insert_locked(node, size, align, 0);
if (ret)
goto err_unlock;
if (transform)
transform(ggtt, node, pte_flags, ggtt->pt_ops->ggtt_set_pte, arg);
else
xe_ggtt_map_bo(ggtt, node, bo, pte_flags);
mutex_unlock(&ggtt->lock);
return node;
err_unlock:
mutex_unlock(&ggtt->lock);
err:
xe_ggtt_node_fini(node);
return ERR_PTR(ret);
}
static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
u64 start, u64 end, struct drm_exec *exec)
{
@@ -815,8 +899,9 @@ static int __xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
} else {
u16 cache_mode = bo->flags & XE_BO_FLAG_NEEDS_UC ? XE_CACHE_NONE : XE_CACHE_WB;
u16 pat_index = tile_to_xe(ggtt->tile)->pat.idx[cache_mode];
u64 pte = ggtt->pt_ops->pte_encode_flags(bo, pat_index);
xe_ggtt_map_bo(ggtt, bo->ggtt_node[tile_id], bo, pat_index);
xe_ggtt_map_bo(ggtt, bo->ggtt_node[tile_id], bo, pte);
}
mutex_unlock(&ggtt->lock);
@@ -890,14 +975,12 @@ u64 xe_ggtt_largest_hole(struct xe_ggtt *ggtt, u64 alignment, u64 *spare)
{
const struct drm_mm *mm = &ggtt->mm;
const struct drm_mm_node *entry;
u64 hole_min_start = xe_wopcm_size(tile_to_xe(ggtt->tile));
u64 hole_start, hole_end, hole_size;
u64 max_hole = 0;
mutex_lock(&ggtt->lock);
drm_mm_for_each_hole(entry, mm, hole_start, hole_end) {
hole_start = max(hole_start, hole_min_start);
hole_start = max(hole_start, ggtt->start);
hole_start = ALIGN(hole_start, alignment);
hole_end = ALIGN_DOWN(hole_end, alignment);
if (hole_start >= hole_end)
@@ -1069,15 +1152,13 @@ u64 xe_ggtt_print_holes(struct xe_ggtt *ggtt, u64 alignment, struct drm_printer
{
const struct drm_mm *mm = &ggtt->mm;
const struct drm_mm_node *entry;
u64 hole_min_start = xe_wopcm_size(tile_to_xe(ggtt->tile));
u64 hole_start, hole_end, hole_size;
u64 total = 0;
char buf[10];
mutex_lock(&ggtt->lock);
drm_mm_for_each_hole(entry, mm, hole_start, hole_end) {
hole_start = max(hole_start, hole_min_start);
hole_start = max(hole_start, ggtt->start);
hole_start = ALIGN(hole_start, alignment);
hole_end = ALIGN_DOWN(hole_end, alignment);
if (hole_start >= hole_end)
@@ -1121,3 +1202,25 @@ u64 xe_ggtt_read_pte(struct xe_ggtt *ggtt, u64 offset)
{
return ioread64(ggtt->gsm + (offset / XE_PAGE_SIZE));
}
/**
* xe_ggtt_node_addr - Get @node offset in GGTT.
* @node: &xe_ggtt_node
*
* Get the GGTT offset for allocated node.
*/
u64 xe_ggtt_node_addr(const struct xe_ggtt_node *node)
{
return node->base.start;
}
/**
* xe_ggtt_node_size - Get @node allocation size.
* @node: &xe_ggtt_node
*
* Get the allocated node's size.
*/
u64 xe_ggtt_node_size(const struct xe_ggtt_node *node)
{
return node->base.size;
}

View File

@@ -23,15 +23,18 @@ int xe_ggtt_node_insert_balloon_locked(struct xe_ggtt_node *node,
u64 start, u64 size);
void xe_ggtt_node_remove_balloon_locked(struct xe_ggtt_node *node);
void xe_ggtt_shift_nodes_locked(struct xe_ggtt *ggtt, s64 shift);
u64 xe_ggtt_start(struct xe_ggtt *ggtt);
u64 xe_ggtt_size(struct xe_ggtt *ggtt);
int xe_ggtt_node_insert(struct xe_ggtt_node *node, u32 size, u32 align);
int xe_ggtt_node_insert_locked(struct xe_ggtt_node *node,
u32 size, u32 align, u32 mm_flags);
struct xe_ggtt_node *
xe_ggtt_node_insert_transform(struct xe_ggtt *ggtt,
struct xe_bo *bo, u64 pte,
u64 size, u32 align,
xe_ggtt_transform_cb transform, void *arg);
void xe_ggtt_node_remove(struct xe_ggtt_node *node, bool invalidate);
bool xe_ggtt_node_allocated(const struct xe_ggtt_node *node);
size_t xe_ggtt_node_pt_size(const struct xe_ggtt_node *node);
void xe_ggtt_map_bo(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
struct xe_bo *bo, u16 pat_index);
void xe_ggtt_map_bo_unlocked(struct xe_ggtt *ggtt, struct xe_bo *bo);
int xe_ggtt_insert_bo(struct xe_ggtt *ggtt, struct xe_bo *bo, struct drm_exec *exec);
int xe_ggtt_insert_bo_at(struct xe_ggtt *ggtt, struct xe_bo *bo,
@@ -58,4 +61,7 @@ void xe_ggtt_might_lock(struct xe_ggtt *ggtt);
u64 xe_ggtt_encode_pte_flags(struct xe_ggtt *ggtt, struct xe_bo *bo, u16 pat_index);
u64 xe_ggtt_read_pte(struct xe_ggtt *ggtt, u64 offset);
u64 xe_ggtt_node_addr(const struct xe_ggtt_node *node);
u64 xe_ggtt_node_size(const struct xe_ggtt_node *node);
#endif

View File

@@ -11,6 +11,7 @@
#include "xe_pt_types.h"
struct xe_bo;
struct xe_ggtt_node;
struct xe_gt;
/**
@@ -22,7 +23,9 @@ struct xe_gt;
struct xe_ggtt {
/** @tile: Back pointer to tile where this GGTT belongs */
struct xe_tile *tile;
/** @size: Total size of this GGTT */
/** @start: Start offset of GGTT */
u64 start;
/** @size: Total usable size of this GGTT */
u64 size;
#define XE_GGTT_FLAGS_64K BIT(0)
@@ -51,24 +54,11 @@ struct xe_ggtt {
struct workqueue_struct *wq;
};
/**
* struct xe_ggtt_node - A node in GGTT.
*
* This struct needs to be initialized (only-once) with xe_ggtt_node_init() before any node
* insertion, reservation, or 'ballooning'.
* It will, then, be finalized by either xe_ggtt_node_remove() or xe_ggtt_node_deballoon().
*/
struct xe_ggtt_node {
/** @ggtt: Back pointer to xe_ggtt where this region will be inserted at */
struct xe_ggtt *ggtt;
/** @base: A drm_mm_node */
struct drm_mm_node base;
/** @delayed_removal_work: The work struct for the delayed removal */
struct work_struct delayed_removal_work;
/** @invalidate_on_remove: If it needs invalidation upon removal */
bool invalidate_on_remove;
};
typedef void (*xe_ggtt_set_pte_fn)(struct xe_ggtt *ggtt, u64 addr, u64 pte);
typedef void (*xe_ggtt_transform_cb)(struct xe_ggtt *ggtt,
struct xe_ggtt_node *node,
u64 pte_flags,
xe_ggtt_set_pte_fn set_pte, void *arg);
/**
* struct xe_ggtt_pt_ops - GGTT Page table operations
* Which can vary from platform to platform.
@@ -76,8 +66,10 @@ struct xe_ggtt_node {
struct xe_ggtt_pt_ops {
/** @pte_encode_flags: Encode PTE flags for a given BO */
u64 (*pte_encode_flags)(struct xe_bo *bo, u16 pat_index);
/** @ggtt_set_pte: Directly write into GGTT's PTE */
void (*ggtt_set_pte)(struct xe_ggtt *ggtt, u64 addr, u64 pte);
xe_ggtt_set_pte_fn ggtt_set_pte;
/** @ggtt_get_pte: Directly read from GGTT's PTE */
u64 (*ggtt_get_pte)(struct xe_ggtt *ggtt, u64 addr);
};

View File

@@ -7,7 +7,7 @@
static void xe_sched_process_msg_queue(struct xe_gpu_scheduler *sched)
{
if (!READ_ONCE(sched->base.pause_submit))
if (!drm_sched_is_stopped(&sched->base))
queue_work(sched->base.submit_wq, &sched->work_process_msg);
}
@@ -43,7 +43,7 @@ static void xe_sched_process_msg_work(struct work_struct *w)
container_of(w, struct xe_gpu_scheduler, work_process_msg);
struct xe_sched_msg *msg;
if (READ_ONCE(sched->base.pause_submit))
if (drm_sched_is_stopped(&sched->base))
return;
msg = xe_sched_get_msg(sched);
@@ -77,6 +77,7 @@ int xe_sched_init(struct xe_gpu_scheduler *sched,
};
sched->ops = xe_ops;
spin_lock_init(&sched->msg_lock);
INIT_LIST_HEAD(&sched->msgs);
INIT_WORK(&sched->work_process_msg, xe_sched_process_msg_work);
@@ -117,7 +118,7 @@ void xe_sched_add_msg(struct xe_gpu_scheduler *sched,
void xe_sched_add_msg_locked(struct xe_gpu_scheduler *sched,
struct xe_sched_msg *msg)
{
lockdep_assert_held(&sched->base.job_list_lock);
lockdep_assert_held(&sched->msg_lock);
list_add_tail(&msg->link, &sched->msgs);
xe_sched_process_msg_queue(sched);
@@ -131,7 +132,7 @@ void xe_sched_add_msg_locked(struct xe_gpu_scheduler *sched,
void xe_sched_add_msg_head(struct xe_gpu_scheduler *sched,
struct xe_sched_msg *msg)
{
lockdep_assert_held(&sched->base.job_list_lock);
lockdep_assert_held(&sched->msg_lock);
list_add(&msg->link, &sched->msgs);
xe_sched_process_msg_queue(sched);

View File

@@ -33,12 +33,12 @@ void xe_sched_add_msg_head(struct xe_gpu_scheduler *sched,
static inline void xe_sched_msg_lock(struct xe_gpu_scheduler *sched)
{
spin_lock(&sched->base.job_list_lock);
spin_lock(&sched->msg_lock);
}
static inline void xe_sched_msg_unlock(struct xe_gpu_scheduler *sched)
{
spin_unlock(&sched->base.job_list_lock);
spin_unlock(&sched->msg_lock);
}
static inline void xe_sched_stop(struct xe_gpu_scheduler *sched)
@@ -56,12 +56,9 @@ static inline void xe_sched_resubmit_jobs(struct xe_gpu_scheduler *sched)
struct drm_sched_job *s_job;
bool restore_replay = false;
list_for_each_entry(s_job, &sched->base.pending_list, list) {
struct drm_sched_fence *s_fence = s_job->s_fence;
struct dma_fence *hw_fence = s_fence->parent;
drm_sched_for_each_pending_job(s_job, &sched->base, NULL) {
restore_replay |= to_xe_sched_job(s_job)->restore_replay;
if (restore_replay || (hw_fence && !dma_fence_is_signaled(hw_fence)))
if (restore_replay || !drm_sched_job_is_signaled(s_job))
sched->base.ops->run_job(s_job);
}
}
@@ -72,14 +69,6 @@ xe_sched_invalidate_job(struct xe_sched_job *job, int threshold)
return drm_sched_invalidate_job(&job->drm, threshold);
}
static inline void xe_sched_add_pending_job(struct xe_gpu_scheduler *sched,
struct xe_sched_job *job)
{
spin_lock(&sched->base.job_list_lock);
list_add(&job->drm.list, &sched->base.pending_list);
spin_unlock(&sched->base.job_list_lock);
}
/**
* xe_sched_first_pending_job() - Find first pending job which is unsignaled
* @sched: Xe GPU scheduler
@@ -89,21 +78,13 @@ static inline void xe_sched_add_pending_job(struct xe_gpu_scheduler *sched,
static inline
struct xe_sched_job *xe_sched_first_pending_job(struct xe_gpu_scheduler *sched)
{
struct xe_sched_job *job, *r_job = NULL;
struct drm_sched_job *job;
spin_lock(&sched->base.job_list_lock);
list_for_each_entry(job, &sched->base.pending_list, drm.list) {
struct drm_sched_fence *s_fence = job->drm.s_fence;
struct dma_fence *hw_fence = s_fence->parent;
drm_sched_for_each_pending_job(job, &sched->base, NULL)
if (!drm_sched_job_is_signaled(job))
return to_xe_sched_job(job);
if (hw_fence && !dma_fence_is_signaled(hw_fence)) {
r_job = job;
break;
}
}
spin_unlock(&sched->base.job_list_lock);
return r_job;
return NULL;
}
static inline int

View File

@@ -47,6 +47,8 @@ struct xe_gpu_scheduler {
const struct xe_sched_backend_ops *ops;
/** @msgs: list of messages to be processed in @work_process_msg */
struct list_head msgs;
/** @msg_lock: Message lock */
spinlock_t msg_lock;
/** @work_process_msg: processes messages */
struct work_struct work_process_msg;
};

View File

@@ -414,15 +414,16 @@ int xe_gsc_init(struct xe_gsc *gsc)
}
/*
* Some platforms can have GuC but not GSC. That would cause
* xe_uc_fw_init(gsc) to return a "not supported" failure code and abort
* all firmware loading. So check for GSC being enabled before
* propagating the failure back up. That way the higher level will keep
* going and load GuC as appropriate.
* Starting from BMG the GSC is no longer needed for MC6 entry, so the
* only missing features if the FW is lacking would be the content
* protection ones. This is acceptable, so we allow the driver load to
* continue if the GSC FW is missing.
*/
ret = xe_uc_fw_init(&gsc->fw);
if (!xe_uc_fw_is_enabled(&gsc->fw))
return 0;
else if (gt_to_xe(gt)->info.platform >= XE_BATTLEMAGE && !xe_uc_fw_is_available(&gsc->fw))
return 0;
else if (ret)
goto out;
@@ -614,7 +615,7 @@ void xe_gsc_print_info(struct xe_gsc *gsc, struct drm_printer *p)
drm_printf(p, "\tfound security version %u\n", gsc->security_version);
if (!xe_uc_fw_is_enabled(&gsc->fw))
if (!xe_uc_fw_is_available(&gsc->fw))
return;
CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC);

View File

@@ -7,11 +7,10 @@
#include <drm/drm_debugfs.h>
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_gt_types.h"
#include "xe_gsc.h"
#include "xe_macros.h"
#include "xe_pm.h"
static struct xe_gt *

View File

@@ -18,8 +18,8 @@
#include "xe_force_wake.h"
#include "xe_gsc.h"
#include "xe_gsc_submit.h"
#include "xe_gt.h"
#include "xe_gt_printk.h"
#include "xe_gt_types.h"
#include "xe_map.h"
#include "xe_mmio.h"
#include "xe_pm.h"

View File

@@ -11,12 +11,10 @@
#include "xe_assert.h"
#include "xe_bb.h"
#include "xe_exec_queue.h"
#include "xe_gt_printk.h"
#include "xe_gt_types.h"
#include "xe_map.h"
#include "xe_sched_job.h"
#include "instructions/xe_gsc_commands.h"
#include "regs/xe_gsc_regs.h"
#define GSC_HDR_SIZE (sizeof(struct intel_gsc_mtl_header)) /* shorthand define */

View File

@@ -13,13 +13,11 @@
#include <generated/xe_wa_oob.h>
#include "instructions/xe_alu_commands.h"
#include "instructions/xe_gfxpipe_commands.h"
#include "instructions/xe_mi_commands.h"
#include "regs/xe_engine_regs.h"
#include "regs/xe_gt_regs.h"
#include "xe_assert.h"
#include "xe_bb.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_eu_stall.h"
#include "xe_exec_queue.h"
@@ -140,6 +138,36 @@ static void xe_gt_disable_host_l2_vram(struct xe_gt *gt)
xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg);
}
static void xe_gt_enable_comp_1wcoh(struct xe_gt *gt)
{
struct xe_device *xe = gt_to_xe(gt);
unsigned int fw_ref;
u32 reg;
if (IS_SRIOV_VF(xe))
return;
if (GRAPHICS_VER(xe) >= 30 && xe->info.has_flat_ccs) {
fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
if (!fw_ref)
return;
reg = xe_gt_mcr_unicast_read_any(gt, XE2_GAMREQSTRM_CTRL);
reg |= EN_CMP_1WCOH;
xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg);
if (xe_gt_is_media_type(gt)) {
xe_mmio_rmw32(&gt->mmio, XE2_GAMWALK_CTRL_MEDIA, 0, EN_CMP_1WCOH_GW);
} else {
reg = xe_gt_mcr_unicast_read_any(gt, XE2_GAMWALK_CTRL_3D);
reg |= EN_CMP_1WCOH_GW;
xe_gt_mcr_multicast_write(gt, XE2_GAMWALK_CTRL_3D, reg);
}
xe_force_wake_put(gt_to_fw(gt), fw_ref);
}
}
static void gt_reset_worker(struct work_struct *w);
static int emit_job_sync(struct xe_exec_queue *q, struct xe_bb *bb,
@@ -466,6 +494,7 @@ static int gt_init_with_gt_forcewake(struct xe_gt *gt)
xe_gt_topology_init(gt);
xe_gt_mcr_init(gt);
xe_gt_enable_host_l2_vram(gt);
xe_gt_enable_comp_1wcoh(gt);
if (xe_gt_is_main_type(gt)) {
err = xe_ggtt_init(gt_to_tile(gt)->mem.ggtt);
@@ -745,6 +774,7 @@ static int do_gt_restart(struct xe_gt *gt)
xe_pat_init(gt);
xe_gt_enable_host_l2_vram(gt);
xe_gt_enable_comp_1wcoh(gt);
xe_gt_mcr_set_implicit_defaults(gt);
xe_reg_sr_apply_mmio(&gt->reg_sr, gt);

View File

@@ -8,12 +8,8 @@
#include "xe_gt_clock.h"
#include "regs/xe_gt_regs.h"
#include "regs/xe_regs.h"
#include "xe_assert.h"
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_gt_types.h"
#include "xe_gt_printk.h"
#include "xe_macros.h"
#include "xe_mmio.h"
#define f19_2_mhz 19200000

View File

@@ -22,7 +22,6 @@
#include "xe_guc_hwconfig.h"
#include "xe_hw_engine.h"
#include "xe_lrc.h"
#include "xe_macros.h"
#include "xe_mocs.h"
#include "xe_pat.h"
#include "xe_pm.h"

View File

@@ -13,7 +13,6 @@
#include "xe_gt_sysfs.h"
#include "xe_guc_pc.h"
#include "regs/xe_gt_regs.h"
#include "xe_macros.h"
#include "xe_mmio.h"
#include "xe_pm.h"
#include "xe_sriov.h"

View File

@@ -7,7 +7,6 @@
#include "regs/xe_gt_regs.h"
#include "xe_assert.h"
#include "xe_gt.h"
#include "xe_gt_printk.h"
#include "xe_gt_topology.h"
#include "xe_gt_types.h"

View File

@@ -24,13 +24,11 @@
#include "xe_guc_buf.h"
#include "xe_guc_ct.h"
#include "xe_guc_db_mgr.h"
#include "xe_guc_fwif.h"
#include "xe_guc_id_mgr.h"
#include "xe_guc_klv_helpers.h"
#include "xe_guc_klv_thresholds_set.h"
#include "xe_guc_submit.h"
#include "xe_lmtt.h"
#include "xe_map.h"
#include "xe_migrate.h"
#include "xe_sriov.h"
#include "xe_ttm_vram_mgr.h"
@@ -284,7 +282,7 @@ static u32 encode_config_ggtt(u32 *cfg, const struct xe_gt_sriov_config *config,
if (!xe_ggtt_node_allocated(node))
return 0;
return encode_ggtt(cfg, node->base.start, node->base.size, details);
return encode_ggtt(cfg, xe_ggtt_node_addr(node), xe_ggtt_node_size(node), details);
}
static u32 encode_config_sched(struct xe_gt *gt, u32 *cfg, u32 n,
@@ -393,8 +391,8 @@ static int pf_push_full_vf_config(struct xe_gt *gt, unsigned int vfid)
xe_gt_assert(gt, num_dwords <= max_cfg_dwords);
if (vfid == PFID) {
u64 ggtt_start = xe_wopcm_size(gt_to_xe(gt));
u64 ggtt_size = gt_to_tile(gt)->mem.ggtt->size - ggtt_start;
u64 ggtt_start = xe_ggtt_start(gt_to_tile(gt)->mem.ggtt);
u64 ggtt_size = xe_ggtt_size(gt_to_tile(gt)->mem.ggtt);
/* plain PF config data will never include a real GGTT region */
xe_gt_assert(gt, !encode_config_ggtt(cfg + num_dwords, config, true));
@@ -545,9 +543,9 @@ static int pf_provision_vf_ggtt(struct xe_gt *gt, unsigned int vfid, u64 size)
xe_ggtt_assign(node, vfid);
xe_gt_sriov_dbg_verbose(gt, "VF%u assigned GGTT %llx-%llx\n",
vfid, node->base.start, node->base.start + node->base.size - 1);
vfid, xe_ggtt_node_addr(node), xe_ggtt_node_addr(node) + size - 1);
err = pf_distribute_config_ggtt(gt->tile, vfid, node->base.start, node->base.size);
err = pf_distribute_config_ggtt(gt->tile, vfid, xe_ggtt_node_addr(node), size);
if (unlikely(err))
goto err;
@@ -564,7 +562,7 @@ static u64 pf_get_vf_config_ggtt(struct xe_gt *gt, unsigned int vfid)
struct xe_ggtt_node *node = config->ggtt_region;
xe_gt_assert(gt, xe_gt_is_main_type(gt));
return xe_ggtt_node_allocated(node) ? node->base.size : 0;
return xe_ggtt_node_allocated(node) ? xe_ggtt_node_size(node) : 0;
}
/**
@@ -3040,11 +3038,12 @@ int xe_gt_sriov_pf_config_print_ggtt(struct xe_gt *gt, struct drm_printer *p)
if (!xe_ggtt_node_allocated(config->ggtt_region))
continue;
string_get_size(config->ggtt_region->base.size, 1, STRING_UNITS_2,
string_get_size(xe_ggtt_node_size(config->ggtt_region), 1, STRING_UNITS_2,
buf, sizeof(buf));
drm_printf(p, "VF%u:\t%#0llx-%#llx\t(%s)\n",
n, config->ggtt_region->base.start,
config->ggtt_region->base.start + config->ggtt_region->base.size - 1,
n, xe_ggtt_node_addr(config->ggtt_region),
xe_ggtt_node_addr(config->ggtt_region) +
xe_ggtt_node_size(config->ggtt_region) - 1,
buf);
}

View File

@@ -8,7 +8,6 @@
#include <drm/drm_print.h>
#include <drm/drm_debugfs.h>
#include "xe_bo.h"
#include "xe_debugfs.h"
#include "xe_device.h"
#include "xe_gt.h"

View File

@@ -14,7 +14,6 @@
#include "xe_gt_sriov_pf.h"
#include "xe_gt_sriov_pf_config.h"
#include "xe_gt_sriov_pf_control.h"
#include "xe_gt_sriov_pf_helpers.h"
#include "xe_gt_sriov_pf_migration.h"
#include "xe_gt_sriov_printk.h"
#include "xe_guc.h"
@@ -25,6 +24,7 @@
#include "xe_sriov.h"
#include "xe_sriov_packet.h"
#include "xe_sriov_packet_types.h"
#include "xe_sriov_pf_helpers.h"
#include "xe_sriov_pf_migration.h"
#define XE_GT_SRIOV_PF_MIGRATION_RING_SIZE 5

View File

@@ -7,7 +7,6 @@
#include "abi/guc_actions_sriov_abi.h"
#include "xe_bo.h"
#include "xe_gt.h"
#include "xe_gt_sriov_pf_helpers.h"
#include "xe_gt_sriov_pf_policy.h"

View File

@@ -5,20 +5,19 @@
#include <drm/drm_managed.h>
#include "abi/guc_actions_sriov_abi.h"
#include "abi/guc_relay_actions_abi.h"
#include "regs/xe_gt_regs.h"
#include "regs/xe_guc_regs.h"
#include "regs/xe_regs.h"
#include "xe_assert.h"
#include "xe_mmio.h"
#include "xe_gt_sriov_printk.h"
#include "xe_gt_sriov_pf_helpers.h"
#include "xe_gt_sriov_pf_service.h"
#include "xe_gt_sriov_pf_service_types.h"
#include "xe_guc_ct.h"
#include "xe_guc_hxg_helpers.h"
#include "xe_sriov.h"
#include "xe_sriov_pf_service.h"
static const struct xe_reg tgl_runtime_regs[] = {

View File

@@ -15,7 +15,6 @@
#include "abi/guc_klvs_abi.h"
#include "abi/guc_relay_actions_abi.h"
#include "regs/xe_gt_regs.h"
#include "regs/xe_gtt_defs.h"
#include "xe_assert.h"
#include "xe_device.h"

View File

@@ -43,10 +43,10 @@ struct xe_gt_sriov_vf_runtime {
};
/**
* xe_gt_sriov_vf_migration - VF migration data.
* struct xe_gt_sriov_vf_migration - VF migration data.
*/
struct xe_gt_sriov_vf_migration {
/** @migration: VF migration recovery worker */
/** @worker: VF migration recovery worker */
struct work_struct worker;
/** @lock: Protects recovery_queued, teardown */
spinlock_t lock;

View File

@@ -7,8 +7,8 @@
#include <drm/drm_print.h>
#include "xe_gt.h"
#include "xe_gt_stats.h"
#include "xe_gt_types.h"
/**
* xe_gt_stats_incr - Increments the specified stats counter
@@ -76,6 +76,11 @@ static const char *const stat_description[__XE_GT_STATS_NUM_IDS] = {
"hw_engine_group_suspend_lr_queue_us"),
DEF_STAT_STR(HW_ENGINE_GROUP_WAIT_DMA_QUEUE_US,
"hw_engine_group_wait_dma_queue_us"),
DEF_STAT_STR(PRL_4K_ENTRY_COUNT, "prl_4k_entry_count"),
DEF_STAT_STR(PRL_64K_ENTRY_COUNT, "prl_64k_entry_count"),
DEF_STAT_STR(PRL_2M_ENTRY_COUNT, "prl_2m_entry_count"),
DEF_STAT_STR(PRL_ISSUED_COUNT, "prl_issued_count"),
DEF_STAT_STR(PRL_ABORTED_COUNT, "prl_aborted_count"),
};
/**

View File

@@ -49,6 +49,11 @@ enum xe_gt_stats_id {
XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_COUNT,
XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_US,
XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_US,
XE_GT_STATS_ID_PRL_4K_ENTRY_COUNT,
XE_GT_STATS_ID_PRL_64K_ENTRY_COUNT,
XE_GT_STATS_ID_PRL_2M_ENTRY_COUNT,
XE_GT_STATS_ID_PRL_ISSUED_COUNT,
XE_GT_STATS_ID_PRL_ABORTED_COUNT,
/* must be the last entry */
__XE_GT_STATS_NUM_IDS,
};

View File

@@ -10,7 +10,7 @@
#include <drm/drm_managed.h>
#include "xe_gt.h"
#include "xe_gt_types.h"
static void xe_gt_sysfs_kobj_release(struct kobject *kobj)
{

View File

@@ -6,7 +6,7 @@
#include <drm/drm_managed.h>
#include <regs/xe_gt_regs.h>
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_gt.h"
#include "xe_gt_sysfs.h"
#include "xe_gt_throttle.h"

View File

@@ -28,8 +28,6 @@
#include "xe_lrc.h"
#include "xe_map.h"
#include "xe_mmio.h"
#include "xe_platform_types.h"
#include "xe_uc_fw.h"
#include "xe_wa.h"
/* Slack of a few additional entries per engine */
@@ -451,7 +449,7 @@ static void guc_policies_init(struct xe_guc_ads *ads)
ads_blob_write(ads, policies.max_num_work_items,
GLOBAL_POLICY_MAX_NUM_WI);
if (xe->wedged.mode == 2)
if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
global_flags |= GLOBAL_POLICY_DISABLE_ENGINE_RESET;
ads_blob_write(ads, policies.global_flags, global_flags);
@@ -983,16 +981,17 @@ static int guc_ads_action_update_policies(struct xe_guc_ads *ads, u32 policy_off
/**
* xe_guc_ads_scheduler_policy_toggle_reset - Toggle reset policy
* @ads: Additional data structures object
* @enable_engine_reset: true to enable engine resets, false otherwise
*
* This function update the GuC's engine reset policy based on wedged.mode.
* This function update the GuC's engine reset policy.
*
* Return: 0 on success, and negative error code otherwise.
*/
int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads)
int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads,
bool enable_engine_reset)
{
struct guc_policies *policies;
struct xe_guc *guc = ads_to_guc(ads);
struct xe_device *xe = ads_to_xe(ads);
CLASS(xe_guc_buf, buf)(&guc->buf, sizeof(*policies));
if (!xe_guc_buf_is_valid(buf))
@@ -1004,10 +1003,11 @@ int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads)
policies->dpc_promote_time = ads_blob_read(ads, policies.dpc_promote_time);
policies->max_num_work_items = ads_blob_read(ads, policies.max_num_work_items);
policies->is_valid = 1;
if (xe->wedged.mode == 2)
policies->global_flags |= GLOBAL_POLICY_DISABLE_ENGINE_RESET;
else
if (enable_engine_reset)
policies->global_flags &= ~GLOBAL_POLICY_DISABLE_ENGINE_RESET;
else
policies->global_flags |= GLOBAL_POLICY_DISABLE_ENGINE_RESET;
return guc_ads_action_update_policies(ads, xe_guc_buf_flush(buf));
}

View File

@@ -6,6 +6,8 @@
#ifndef _XE_GUC_ADS_H_
#define _XE_GUC_ADS_H_
#include <linux/types.h>
struct xe_guc_ads;
int xe_guc_ads_init(struct xe_guc_ads *ads);
@@ -13,6 +15,7 @@ int xe_guc_ads_init_post_hwconfig(struct xe_guc_ads *ads);
void xe_guc_ads_populate(struct xe_guc_ads *ads);
void xe_guc_ads_populate_minimal(struct xe_guc_ads *ads);
void xe_guc_ads_populate_post_load(struct xe_guc_ads *ads);
int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads);
int xe_guc_ads_scheduler_policy_toggle_reset(struct xe_guc_ads *ads,
bool enable_engine_reset);
#endif

View File

@@ -6,7 +6,6 @@
#include <linux/cleanup.h>
#include <drm/drm_managed.h>
#include "xe_assert.h"
#include "xe_bo.h"
#include "xe_gt_printk.h"
#include "xe_guc.h"

View File

@@ -13,17 +13,14 @@
#include "abi/guc_log_abi.h"
#include "regs/xe_engine_regs.h"
#include "regs/xe_gt_regs.h"
#include "regs/xe_guc_regs.h"
#include "regs/xe_regs.h"
#include "xe_bo.h"
#include "xe_bo_types.h"
#include "xe_device.h"
#include "xe_exec_queue_types.h"
#include "xe_gt.h"
#include "xe_gt_mcr.h"
#include "xe_gt_printk.h"
#include "xe_guc.h"
#include "xe_guc_ads.h"
#include "xe_guc_capture.h"
#include "xe_guc_capture_types.h"
#include "xe_guc_ct.h"
@@ -1889,7 +1886,14 @@ xe_guc_capture_get_matching_and_lock(struct xe_exec_queue *q)
return NULL;
xe = gt_to_xe(q->gt);
if (xe->wedged.mode >= 2 || !xe_device_uc_enabled(xe) || IS_SRIOV_VF(xe))
if (xe->wedged.mode == XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
return NULL;
if (!xe_device_uc_enabled(xe))
return NULL;
if (IS_SRIOV_VF(xe))
return NULL;
ss = &xe->devcoredump.snapshot;

View File

@@ -8,13 +8,12 @@
#include <drm/drm_debugfs.h>
#include <drm/drm_managed.h>
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_device_types.h"
#include "xe_gt_types.h"
#include "xe_guc.h"
#include "xe_guc_ct.h"
#include "xe_guc_log.h"
#include "xe_guc_pc.h"
#include "xe_macros.h"
#include "xe_pm.h"
/*

View File

@@ -33,8 +33,6 @@ struct xe_guc_exec_queue {
*/
#define MAX_STATIC_MSG_TYPE 3
struct xe_sched_msg static_msgs[MAX_STATIC_MSG_TYPE];
/** @lr_tdr: long running TDR worker */
struct work_struct lr_tdr;
/** @destroy_async: do final destroy async from this worker */
struct work_struct destroy_async;
/** @resume_time: time of last resume */

View File

@@ -10,8 +10,8 @@
#include "abi/guc_actions_abi.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_device_types.h"
#include "xe_gt_types.h"
#include "xe_guc.h"
#include "xe_map.h"

View File

@@ -15,8 +15,8 @@
#include "xe_bo.h"
#include "xe_devcoredump.h"
#include "xe_force_wake.h"
#include "xe_gt.h"
#include "xe_gt_printk.h"
#include "xe_gt_types.h"
#include "xe_map.h"
#include "xe_mmio.h"
#include "xe_module.h"

View File

@@ -17,8 +17,7 @@
#include "abi/guc_relay_communication_abi.h"
#include "xe_assert.h"
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_device_types.h"
#include "xe_gt_sriov_printk.h"
#include "xe_gt_sriov_pf_service.h"
#include "xe_guc.h"

View File

@@ -17,7 +17,6 @@
#include "abi/guc_actions_abi.h"
#include "abi/guc_actions_slpc_abi.h"
#include "abi/guc_klvs_abi.h"
#include "regs/xe_lrc_layout.h"
#include "xe_assert.h"
#include "xe_bo.h"
#include "xe_devcoredump.h"
@@ -36,7 +35,6 @@
#include "xe_guc_klv_helpers.h"
#include "xe_guc_submit_types.h"
#include "xe_hw_engine.h"
#include "xe_hw_fence.h"
#include "xe_lrc.h"
#include "xe_macros.h"
#include "xe_map.h"
@@ -71,11 +69,8 @@ exec_queue_to_guc(struct xe_exec_queue *q)
#define EXEC_QUEUE_STATE_KILLED (1 << 7)
#define EXEC_QUEUE_STATE_WEDGED (1 << 8)
#define EXEC_QUEUE_STATE_BANNED (1 << 9)
#define EXEC_QUEUE_STATE_CHECK_TIMEOUT (1 << 10)
#define EXEC_QUEUE_STATE_EXTRA_REF (1 << 11)
#define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 12)
#define EXEC_QUEUE_STATE_PENDING_TDR_EXIT (1 << 13)
#define EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND (1 << 14)
#define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 10)
#define EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND (1 << 11)
static bool exec_queue_registered(struct xe_exec_queue *q)
{
@@ -207,36 +202,6 @@ static void set_exec_queue_wedged(struct xe_exec_queue *q)
atomic_or(EXEC_QUEUE_STATE_WEDGED, &q->guc->state);
}
static bool exec_queue_check_timeout(struct xe_exec_queue *q)
{
return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_CHECK_TIMEOUT;
}
static void set_exec_queue_check_timeout(struct xe_exec_queue *q)
{
atomic_or(EXEC_QUEUE_STATE_CHECK_TIMEOUT, &q->guc->state);
}
static void clear_exec_queue_check_timeout(struct xe_exec_queue *q)
{
atomic_and(~EXEC_QUEUE_STATE_CHECK_TIMEOUT, &q->guc->state);
}
static bool exec_queue_extra_ref(struct xe_exec_queue *q)
{
return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_EXTRA_REF;
}
static void set_exec_queue_extra_ref(struct xe_exec_queue *q)
{
atomic_or(EXEC_QUEUE_STATE_EXTRA_REF, &q->guc->state);
}
static void clear_exec_queue_extra_ref(struct xe_exec_queue *q)
{
atomic_and(~EXEC_QUEUE_STATE_EXTRA_REF, &q->guc->state);
}
static bool exec_queue_pending_resume(struct xe_exec_queue *q)
{
return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_PENDING_RESUME;
@@ -252,21 +217,6 @@ static void clear_exec_queue_pending_resume(struct xe_exec_queue *q)
atomic_and(~EXEC_QUEUE_STATE_PENDING_RESUME, &q->guc->state);
}
static bool exec_queue_pending_tdr_exit(struct xe_exec_queue *q)
{
return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_PENDING_TDR_EXIT;
}
static void set_exec_queue_pending_tdr_exit(struct xe_exec_queue *q)
{
atomic_or(EXEC_QUEUE_STATE_PENDING_TDR_EXIT, &q->guc->state);
}
static void clear_exec_queue_pending_tdr_exit(struct xe_exec_queue *q)
{
atomic_and(~EXEC_QUEUE_STATE_PENDING_TDR_EXIT, &q->guc->state);
}
static bool exec_queue_idle_skip_suspend(struct xe_exec_queue *q)
{
return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND;
@@ -603,10 +553,7 @@ static void xe_guc_exec_queue_trigger_cleanup(struct xe_exec_queue *q)
/** to wakeup xe_wait_user_fence ioctl if exec queue is reset */
wake_up_all(&xe->ufence_wq);
if (xe_exec_queue_is_lr(q))
queue_work(guc_to_gt(guc)->ordered_wq, &q->guc->lr_tdr);
else
xe_sched_tdr_queue_imm(&q->guc->sched);
xe_sched_tdr_queue_imm(&q->guc->sched);
}
static void xe_guc_exec_queue_group_trigger_cleanup(struct xe_exec_queue *q)
@@ -639,19 +586,19 @@ static void xe_guc_exec_queue_reset_trigger_cleanup(struct xe_exec_queue *q)
WRITE_ONCE(group->banned, true);
set_exec_queue_reset(primary);
if (!exec_queue_banned(primary) && !exec_queue_check_timeout(primary))
if (!exec_queue_banned(primary))
xe_guc_exec_queue_trigger_cleanup(primary);
mutex_lock(&group->list_lock);
list_for_each_entry(eq, &group->list, multi_queue.link) {
set_exec_queue_reset(eq);
if (!exec_queue_banned(eq) && !exec_queue_check_timeout(eq))
if (!exec_queue_banned(eq))
xe_guc_exec_queue_trigger_cleanup(eq);
}
mutex_unlock(&group->list_lock);
} else {
set_exec_queue_reset(q);
if (!exec_queue_banned(q) && !exec_queue_check_timeout(q))
if (!exec_queue_banned(q))
xe_guc_exec_queue_trigger_cleanup(q);
}
}
@@ -994,14 +941,6 @@ static void register_exec_queue(struct xe_exec_queue *q, int ctx_type)
parallel_write(xe, map, wq_desc.wq_status, WQ_STATUS_ACTIVE);
}
/*
* We must keep a reference for LR engines if engine is registered with
* the GuC as jobs signal immediately and can't destroy an engine if the
* GuC has a reference to it.
*/
if (xe_exec_queue_is_lr(q))
xe_exec_queue_get(q);
set_exec_queue_registered(q);
trace_xe_exec_queue_register(q);
if (xe_exec_queue_is_multi_queue_primary(q))
@@ -1202,7 +1141,7 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job)
struct xe_sched_job *job = to_xe_sched_job(drm_job);
struct xe_exec_queue *q = job->q;
struct xe_guc *guc = exec_queue_to_guc(q);
bool lr = xe_exec_queue_is_lr(q), killed_or_banned_or_wedged =
bool killed_or_banned_or_wedged =
exec_queue_killed_or_banned_or_wedged(q);
xe_gt_assert(guc_to_gt(guc), !(exec_queue_destroyed(q) || exec_queue_pending_disable(q)) ||
@@ -1232,14 +1171,6 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job)
}
run_job_out:
/*
* We don't care about job-fence ordering in LR VMs because these fences
* are never exported; they are used solely to keep jobs on the pending
* list. Once a queue enters an error state, there's no need to track
* them.
*/
if (killed_or_banned_or_wedged && lr)
xe_sched_job_set_error(job, -ECANCELED);
return job->fence;
}
@@ -1291,8 +1222,7 @@ static void disable_scheduling_deregister(struct xe_guc *guc,
xe_gt_warn(q->gt, "Pending enable/disable failed to respond\n");
xe_sched_submission_start(sched);
xe_gt_reset_async(q->gt);
if (!xe_exec_queue_is_lr(q))
xe_sched_tdr_queue_imm(sched);
xe_sched_tdr_queue_imm(sched);
return;
}
@@ -1339,8 +1269,9 @@ void xe_guc_submit_wedge(struct xe_guc *guc)
err = devm_add_action_or_reset(guc_to_xe(guc)->drm.dev,
guc_submit_wedged_fini, guc);
if (err) {
xe_gt_err(gt, "Failed to register clean-up on wedged.mode=2; "
"Although device is wedged.\n");
xe_gt_err(gt, "Failed to register clean-up in wedged.mode=%s; "
"Although device is wedged.\n",
xe_wedged_mode_to_string(XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET));
return;
}
@@ -1355,7 +1286,7 @@ static bool guc_submit_hint_wedged(struct xe_guc *guc)
{
struct xe_device *xe = guc_to_xe(guc);
if (xe->wedged.mode != 2)
if (xe->wedged.mode != XE_WEDGED_MODE_UPON_ANY_HANG_NO_RESET)
return false;
if (xe_device_wedged(xe))
@@ -1366,84 +1297,6 @@ static bool guc_submit_hint_wedged(struct xe_guc *guc)
return true;
}
static void xe_guc_exec_queue_lr_cleanup(struct work_struct *w)
{
struct xe_guc_exec_queue *ge =
container_of(w, struct xe_guc_exec_queue, lr_tdr);
struct xe_exec_queue *q = ge->q;
struct xe_guc *guc = exec_queue_to_guc(q);
struct xe_gpu_scheduler *sched = &ge->sched;
struct xe_sched_job *job;
bool wedged = false;
xe_gt_assert(guc_to_gt(guc), xe_exec_queue_is_lr(q));
if (vf_recovery(guc))
return;
trace_xe_exec_queue_lr_cleanup(q);
if (!exec_queue_killed(q))
wedged = guc_submit_hint_wedged(exec_queue_to_guc(q));
/* Kill the run_job / process_msg entry points */
xe_sched_submission_stop(sched);
/*
* Engine state now mostly stable, disable scheduling / deregister if
* needed. This cleanup routine might be called multiple times, where
* the actual async engine deregister drops the final engine ref.
* Calling disable_scheduling_deregister will mark the engine as
* destroyed and fire off the CT requests to disable scheduling /
* deregister, which we only want to do once. We also don't want to mark
* the engine as pending_disable again as this may race with the
* xe_guc_deregister_done_handler() which treats it as an unexpected
* state.
*/
if (!wedged && exec_queue_registered(q) && !exec_queue_destroyed(q)) {
struct xe_guc *guc = exec_queue_to_guc(q);
int ret;
set_exec_queue_banned(q);
disable_scheduling_deregister(guc, q);
/*
* Must wait for scheduling to be disabled before signalling
* any fences, if GT broken the GT reset code should signal us.
*/
ret = wait_event_timeout(guc->ct.wq,
!exec_queue_pending_disable(q) ||
xe_guc_read_stopped(guc) ||
vf_recovery(guc), HZ * 5);
if (vf_recovery(guc))
return;
if (!ret) {
xe_gt_warn(q->gt, "Schedule disable failed to respond, guc_id=%d\n",
q->guc->id);
xe_devcoredump(q, NULL, "Schedule disable failed to respond, guc_id=%d\n",
q->guc->id);
xe_sched_submission_start(sched);
xe_gt_reset_async(q->gt);
return;
}
}
if (!exec_queue_killed(q) && !xe_lrc_ring_is_idle(q->lrc[0]))
xe_devcoredump(q, NULL, "LR job cleanup, guc_id=%d", q->guc->id);
xe_hw_fence_irq_stop(q->fence_irq);
xe_sched_submission_start(sched);
spin_lock(&sched->base.job_list_lock);
list_for_each_entry(job, &sched->base.pending_list, drm.list)
xe_sched_job_set_error(job, -ECANCELED);
spin_unlock(&sched->base.job_list_lock);
xe_hw_fence_irq_start(q->fence_irq);
}
#define ADJUST_FIVE_PERCENT(__t) mul_u64_u32_div(__t, 105, 100)
static bool check_timeout(struct xe_exec_queue *q, struct xe_sched_job *job)
@@ -1462,7 +1315,16 @@ static bool check_timeout(struct xe_exec_queue *q, struct xe_sched_job *job)
return xe_sched_invalidate_job(job, 2);
}
ctx_timestamp = lower_32_bits(xe_lrc_ctx_timestamp(q->lrc[0]));
ctx_timestamp = lower_32_bits(xe_lrc_timestamp(q->lrc[0]));
if (ctx_timestamp == job->sample_timestamp) {
xe_gt_warn(gt, "Check job timeout: seqno=%u, lrc_seqno=%u, guc_id=%d, timestamp stuck",
xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job),
q->guc->id);
return xe_sched_invalidate_job(job, 0);
}
job->sample_timestamp = ctx_timestamp;
ctx_job_timestamp = xe_lrc_ctx_job_timestamp(q->lrc[0]);
/*
@@ -1516,8 +1378,7 @@ static void enable_scheduling(struct xe_exec_queue *q)
xe_gt_warn(guc_to_gt(guc), "Schedule enable failed to respond");
set_exec_queue_banned(q);
xe_gt_reset_async(q->gt);
if (!xe_exec_queue_is_lr(q))
xe_sched_tdr_queue_imm(&q->guc->sched);
xe_sched_tdr_queue_imm(&q->guc->sched);
}
}
@@ -1543,33 +1404,11 @@ static void disable_scheduling(struct xe_exec_queue *q, bool immediate)
G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, 1);
}
static void __deregister_exec_queue(struct xe_guc *guc, struct xe_exec_queue *q)
{
u32 action[] = {
XE_GUC_ACTION_DEREGISTER_CONTEXT,
q->guc->id,
};
xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q));
xe_gt_assert(guc_to_gt(guc), exec_queue_registered(q));
xe_gt_assert(guc_to_gt(guc), !exec_queue_pending_enable(q));
xe_gt_assert(guc_to_gt(guc), !exec_queue_pending_disable(q));
set_exec_queue_destroyed(q);
trace_xe_exec_queue_deregister(q);
if (xe_exec_queue_is_multi_queue_secondary(q))
handle_deregister_done(guc, q);
else
xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action),
G2H_LEN_DW_DEREGISTER_CONTEXT, 1);
}
static enum drm_gpu_sched_stat
guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
{
struct xe_sched_job *job = to_xe_sched_job(drm_job);
struct xe_sched_job *tmp_job;
struct drm_sched_job *tmp_job;
struct xe_exec_queue *q = job->q;
struct xe_gpu_scheduler *sched = &q->guc->sched;
struct xe_guc *guc = exec_queue_to_guc(q);
@@ -1577,10 +1416,9 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
struct xe_device *xe = guc_to_xe(guc);
int err = -ETIME;
pid_t pid = -1;
int i = 0;
bool wedged = false, skip_timeout_check;
xe_gt_assert(guc_to_gt(guc), !xe_exec_queue_is_lr(q));
xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q));
/*
* TDR has fired before free job worker. Common if exec queue
@@ -1597,14 +1435,17 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
/* Must check all state after stopping scheduler */
skip_timeout_check = exec_queue_reset(q) ||
exec_queue_killed_or_banned_or_wedged(q) ||
exec_queue_destroyed(q);
exec_queue_killed_or_banned_or_wedged(q);
/* Skip timeout check if multi-queue group is banned */
if (xe_exec_queue_is_multi_queue(q) &&
READ_ONCE(q->multi_queue.group->banned))
skip_timeout_check = true;
/* LR jobs can only get here if queue has been killed or hit an error */
if (xe_exec_queue_is_lr(q))
xe_gt_assert(guc_to_gt(guc), skip_timeout_check);
/*
* FIXME: In multi-queue scenario, the TDR must ensure that the whole
* multi-queue group is off the HW before signaling the fences to avoid
@@ -1628,23 +1469,24 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
}
/*
* XXX: Sampling timeout doesn't work in wedged mode as we have to
* modify scheduling state to read timestamp. We could read the
* timestamp from a register to accumulate current running time but this
* doesn't work for SRIOV. For now assuming timeouts in wedged mode are
* genuine timeouts.
* Check if job is actually timed out, if so restart job execution and TDR
*/
if (!skip_timeout_check && !check_timeout(q, job))
goto rearm;
if (!exec_queue_killed(q))
wedged = guc_submit_hint_wedged(exec_queue_to_guc(q));
/* Engine state now stable, disable scheduling to check timestamp */
if (!wedged && exec_queue_registered(q)) {
set_exec_queue_banned(q);
/* Kick job / queue off hardware */
if (!wedged && (exec_queue_enabled(q) || exec_queue_pending_disable(q))) {
int ret;
if (exec_queue_reset(q))
err = -EIO;
if (!exec_queue_destroyed(q)) {
if (xe_uc_fw_is_running(&guc->fw)) {
/*
* Wait for any pending G2H to flush out before
* modifying state
@@ -1659,13 +1501,6 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
if (!ret || xe_guc_read_stopped(guc))
goto trigger_reset;
/*
* Flag communicates to G2H handler that schedule
* disable originated from a timeout check. The G2H then
* avoid triggering cleanup or deregistering the exec
* queue.
*/
set_exec_queue_check_timeout(q);
disable_scheduling(q, skip_timeout_check);
}
@@ -1679,6 +1514,7 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job)
*/
smp_rmb();
ret = wait_event_timeout(guc->ct.wq,
!xe_uc_fw_is_running(&guc->fw) ||
!exec_queue_pending_disable(q) ||
xe_guc_read_stopped(guc) ||
vf_recovery(guc), HZ * 5);
@@ -1693,24 +1529,12 @@ trigger_reset:
xe_devcoredump(q, job,
"Schedule disable failed to respond, guc_id=%d, ret=%d, guc_read=%d",
q->guc->id, ret, xe_guc_read_stopped(guc));
set_exec_queue_extra_ref(q);
xe_exec_queue_get(q); /* GT reset owns this */
set_exec_queue_banned(q);
xe_gt_reset_async(q->gt);
xe_sched_tdr_queue_imm(sched);
goto rearm;
}
}
/*
* Check if job is actually timed out, if so restart job execution and TDR
*/
if (!wedged && !skip_timeout_check && !check_timeout(q, job) &&
!exec_queue_reset(q) && exec_queue_registered(q)) {
clear_exec_queue_check_timeout(q);
goto sched_enable;
}
if (q->vm && q->vm->xef) {
process_name = q->vm->xef->process_name;
pid = q->vm->xef->pid;
@@ -1741,28 +1565,16 @@ trigger_reset:
if (!wedged && (q->flags & EXEC_QUEUE_FLAG_KERNEL ||
(q->flags & EXEC_QUEUE_FLAG_VM && !exec_queue_killed(q)))) {
if (!xe_sched_invalidate_job(job, 2)) {
clear_exec_queue_check_timeout(q);
xe_gt_reset_async(q->gt);
goto rearm;
}
}
/* Finish cleaning up exec queue via deregister */
set_exec_queue_banned(q);
if (!wedged && exec_queue_registered(q) && !exec_queue_destroyed(q)) {
set_exec_queue_extra_ref(q);
xe_exec_queue_get(q);
__deregister_exec_queue(guc, q);
}
/* Mark all outstanding jobs as bad, thus completing them */
xe_sched_job_set_error(job, err);
drm_sched_for_each_pending_job(tmp_job, &sched->base, NULL)
xe_sched_job_set_error(to_xe_sched_job(tmp_job), -ECANCELED);
/* Stop fence signaling */
xe_hw_fence_irq_stop(q->fence_irq);
/*
* Fence state now stable, stop / start scheduler which cleans up any
* fences that are complete
*/
xe_sched_add_pending_job(sched, job);
xe_sched_submission_start(sched);
if (xe_exec_queue_is_multi_queue(q))
@@ -1770,20 +1582,12 @@ trigger_reset:
else
xe_guc_exec_queue_trigger_cleanup(q);
/* Mark all outstanding jobs as bad, thus completing them */
spin_lock(&sched->base.job_list_lock);
list_for_each_entry(tmp_job, &sched->base.pending_list, drm.list)
xe_sched_job_set_error(tmp_job, !i++ ? err : -ECANCELED);
spin_unlock(&sched->base.job_list_lock);
/*
* We want the job added back to the pending list so it gets freed; this
* is what DRM_GPU_SCHED_STAT_NO_HANG does.
*/
return DRM_GPU_SCHED_STAT_NO_HANG;
/* Start fence signaling */
xe_hw_fence_irq_start(q->fence_irq);
return DRM_GPU_SCHED_STAT_RESET;
sched_enable:
set_exec_queue_pending_tdr_exit(q);
enable_scheduling(q);
rearm:
/*
* XXX: Ideally want to adjust timeout based on current execution time
@@ -1829,8 +1633,6 @@ static void __guc_exec_queue_destroy_async(struct work_struct *w)
mutex_unlock(&group->list_lock);
}
if (xe_exec_queue_is_lr(q))
cancel_work_sync(&ge->lr_tdr);
/* Confirm no work left behind accessing device structures */
cancel_delayed_work_sync(&ge->sched.base.work_tdr);
@@ -2134,9 +1936,6 @@ static int guc_exec_queue_init(struct xe_exec_queue *q)
if (err)
goto err_sched;
if (xe_exec_queue_is_lr(q))
INIT_WORK(&q->guc->lr_tdr, xe_guc_exec_queue_lr_cleanup);
mutex_lock(&guc->submission_state.lock);
err = alloc_guc_id(guc, q);
@@ -2432,9 +2231,7 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q)
/* Clean up lost G2H + reset engine state */
if (exec_queue_registered(q)) {
if (exec_queue_extra_ref(q) || xe_exec_queue_is_lr(q))
xe_exec_queue_put(q);
else if (exec_queue_destroyed(q))
if (exec_queue_destroyed(q))
__guc_exec_queue_destroy(guc, q);
}
if (q->guc->suspend_pending) {
@@ -2464,9 +2261,6 @@ static void guc_exec_queue_stop(struct xe_guc *guc, struct xe_exec_queue *q)
trace_xe_sched_job_ban(job);
ban = true;
}
} else if (xe_exec_queue_is_lr(q) &&
!xe_lrc_ring_is_idle(q->lrc[0])) {
ban = true;
}
if (ban) {
@@ -2546,11 +2340,8 @@ static void guc_exec_queue_revert_pending_state_change(struct xe_guc *guc,
q->guc->id);
}
if (pending_enable && !pending_resume &&
!exec_queue_pending_tdr_exit(q)) {
if (pending_enable && !pending_resume) {
clear_exec_queue_registered(q);
if (xe_exec_queue_is_lr(q))
xe_exec_queue_put(q);
xe_gt_dbg(guc_to_gt(guc), "Replay REGISTER - guc_id=%d",
q->guc->id);
}
@@ -2558,7 +2349,6 @@ static void guc_exec_queue_revert_pending_state_change(struct xe_guc *guc,
if (pending_enable) {
clear_exec_queue_enabled(q);
clear_exec_queue_pending_resume(q);
clear_exec_queue_pending_tdr_exit(q);
clear_exec_queue_pending_enable(q);
xe_gt_dbg(guc_to_gt(guc), "Replay ENABLE - guc_id=%d",
q->guc->id);
@@ -2566,11 +2356,7 @@ static void guc_exec_queue_revert_pending_state_change(struct xe_guc *guc,
if (exec_queue_destroyed(q) && exec_queue_registered(q)) {
clear_exec_queue_destroyed(q);
if (exec_queue_extra_ref(q))
xe_exec_queue_put(q);
else
q->guc->needs_cleanup = true;
clear_exec_queue_extra_ref(q);
q->guc->needs_cleanup = true;
xe_gt_dbg(guc_to_gt(guc), "Replay CLEANUP - guc_id=%d",
q->guc->id);
}
@@ -2588,7 +2374,6 @@ static void guc_exec_queue_revert_pending_state_change(struct xe_guc *guc,
if (!pending_enable)
set_exec_queue_enabled(q);
clear_exec_queue_pending_disable(q);
clear_exec_queue_check_timeout(q);
xe_gt_dbg(guc_to_gt(guc), "Replay DISABLE - guc_id=%d",
q->guc->id);
}
@@ -2623,10 +2408,7 @@ static void guc_exec_queue_pause(struct xe_guc *guc, struct xe_exec_queue *q)
/* Stop scheduling + flush any DRM scheduler operations */
xe_sched_submission_stop(sched);
if (xe_exec_queue_is_lr(q))
cancel_work_sync(&q->guc->lr_tdr);
else
cancel_delayed_work_sync(&sched->base.work_tdr);
cancel_delayed_work_sync(&sched->base.work_tdr);
guc_exec_queue_revert_pending_state_change(guc, q);
@@ -2753,11 +2535,12 @@ static void guc_exec_queue_unpause_prepare(struct xe_guc *guc,
struct xe_exec_queue *q)
{
struct xe_gpu_scheduler *sched = &q->guc->sched;
struct xe_sched_job *job = NULL, *__job;
struct xe_sched_job *job = NULL;
struct drm_sched_job *s_job;
bool restore_replay = false;
list_for_each_entry(__job, &sched->base.pending_list, drm.list) {
job = __job;
drm_sched_for_each_pending_job(s_job, &sched->base, NULL) {
job = to_xe_sched_job(s_job);
restore_replay |= job->restore_replay;
if (restore_replay) {
xe_gt_dbg(guc_to_gt(guc), "Replay JOB - guc_id=%d, seqno=%d",
@@ -2881,7 +2664,7 @@ void xe_guc_submit_unpause_vf(struct xe_guc *guc)
* created after resfix done.
*/
if (q->guc->id != index ||
!READ_ONCE(q->guc->sched.base.pause_submit))
!drm_sched_is_stopped(&q->guc->sched.base))
continue;
guc_exec_queue_unpause(guc, q);
@@ -2967,13 +2750,10 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q,
q->guc->resume_time = ktime_get();
clear_exec_queue_pending_resume(q);
clear_exec_queue_pending_tdr_exit(q);
clear_exec_queue_pending_enable(q);
smp_wmb();
wake_up_all(&guc->ct.wq);
} else {
bool check_timeout = exec_queue_check_timeout(q);
xe_gt_assert(guc_to_gt(guc), runnable_state == 0);
xe_gt_assert(guc_to_gt(guc), exec_queue_pending_disable(q));
@@ -2981,11 +2761,11 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q,
suspend_fence_signal(q);
clear_exec_queue_pending_disable(q);
} else {
if (exec_queue_banned(q) || check_timeout) {
if (exec_queue_banned(q)) {
smp_wmb();
wake_up_all(&guc->ct.wq);
}
if (!check_timeout && exec_queue_destroyed(q)) {
if (exec_queue_destroyed(q)) {
/*
* Make sure to clear the pending_disable only
* after sampling the destroyed state. We want
@@ -3048,11 +2828,7 @@ static void handle_deregister_done(struct xe_guc *guc, struct xe_exec_queue *q)
trace_xe_exec_queue_deregister_done(q);
clear_exec_queue_registered(q);
if (exec_queue_extra_ref(q) || xe_exec_queue_is_lr(q))
xe_exec_queue_put(q);
else
__guc_exec_queue_destroy(guc, q);
__guc_exec_queue_destroy(guc, q);
}
int xe_guc_deregister_done_handler(struct xe_guc *guc, u32 *msg, u32 len)
@@ -3386,29 +3162,6 @@ xe_guc_exec_queue_snapshot_capture(struct xe_exec_queue *q)
snapshot->multi_queue.primary = xe_exec_queue_multi_queue_primary(q)->guc->id;
snapshot->multi_queue.pos = q->multi_queue.pos;
}
spin_lock(&sched->base.job_list_lock);
snapshot->pending_list_size = list_count_nodes(&sched->base.pending_list);
snapshot->pending_list = kmalloc_array(snapshot->pending_list_size,
sizeof(struct pending_list_snapshot),
GFP_ATOMIC);
if (snapshot->pending_list) {
struct xe_sched_job *job_iter;
i = 0;
list_for_each_entry(job_iter, &sched->base.pending_list, drm.list) {
snapshot->pending_list[i].seqno =
xe_sched_job_seqno(job_iter);
snapshot->pending_list[i].fence =
dma_fence_is_signaled(job_iter->fence) ? 1 : 0;
snapshot->pending_list[i].finished =
dma_fence_is_signaled(&job_iter->drm.s_fence->finished)
? 1 : 0;
i++;
}
}
spin_unlock(&sched->base.job_list_lock);
return snapshot;
}
@@ -3472,13 +3225,6 @@ xe_guc_exec_queue_snapshot_print(struct xe_guc_submit_exec_queue_snapshot *snaps
drm_printf(p, "\tMulti queue primary GuC ID: %d\n", snapshot->multi_queue.primary);
drm_printf(p, "\tMulti queue position: %d\n", snapshot->multi_queue.pos);
}
for (i = 0; snapshot->pending_list && i < snapshot->pending_list_size;
i++)
drm_printf(p, "\tJob: seqno=%d, fence=%d, finished=%d\n",
snapshot->pending_list[i].seqno,
snapshot->pending_list[i].fence,
snapshot->pending_list[i].finished);
}
/**
@@ -3501,7 +3247,6 @@ void xe_guc_exec_queue_snapshot_free(struct xe_guc_submit_exec_queue_snapshot *s
xe_lrc_snapshot_free(snapshot->lrc[i]);
kfree(snapshot->lrc);
}
kfree(snapshot->pending_list);
kfree(snapshot);
}

View File

@@ -61,12 +61,6 @@ struct guc_submit_parallel_scratch {
u32 wq[WQ_SIZE / sizeof(u32)];
};
struct pending_list_snapshot {
u32 seqno;
bool fence;
bool finished;
};
/**
* struct xe_guc_submit_exec_queue_snapshot - Snapshot for devcoredump
*/
@@ -147,11 +141,6 @@ struct xe_guc_submit_exec_queue_snapshot {
/** @valid: The exec queue is part of a multi queue group */
bool valid;
} multi_queue;
/** @pending_list_size: Size of the pending list snapshot array */
int pending_list_size;
/** @pending_list: snapshot of the pending list info */
struct pending_list_snapshot *pending_list;
};
#endif

View File

@@ -97,6 +97,7 @@ static int send_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval, u32 seqno)
static int send_page_reclaim(struct xe_guc *guc, u32 seqno,
u64 gpu_addr)
{
struct xe_gt *gt = guc_to_gt(guc);
u32 action[] = {
XE_GUC_ACTION_PAGE_RECLAMATION,
seqno,
@@ -104,6 +105,8 @@ static int send_page_reclaim(struct xe_guc *guc, u32 seqno,
upper_32_bits(gpu_addr),
};
xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_ISSUED_COUNT, 1);
return xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action),
G2H_LEN_DW_PAGE_RECLAMATION, 1);
}

View File

@@ -11,7 +11,6 @@
#include <drm/drm_print.h>
#include "xe_device_types.h"
#include "xe_drv.h"
#include "xe_heci_gsc.h"
#include "regs/xe_gsc_regs.h"
#include "xe_platform_types.h"

View File

@@ -12,7 +12,6 @@
#include "abi/gsc_pxp_commands_abi.h"
#include "regs/xe_gsc_regs.h"
#include "regs/xe_guc_regs.h"
#include "xe_assert.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_force_wake.h"

View File

@@ -7,11 +7,10 @@
#include <drm/drm_debugfs.h>
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_gt_types.h"
#include "xe_huc.h"
#include "xe_macros.h"
#include "xe_pm.h"
static struct xe_gt *

View File

@@ -33,7 +33,6 @@
#include "xe_hw_fence.h"
#include "xe_irq.h"
#include "xe_lrc.h"
#include "xe_macros.h"
#include "xe_mmio.h"
#include "xe_reg_sr.h"
#include "xe_reg_whitelist.h"

View File

@@ -7,7 +7,7 @@
#include <linux/kobject.h>
#include <linux/sysfs.h>
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_gt.h"
#include "xe_hw_engine_class_sysfs.h"
#include "xe_pm.h"

View File

@@ -6,7 +6,7 @@
#include <drm/drm_managed.h>
#include "xe_assert.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_exec_queue.h"
#include "xe_gt.h"
#include "xe_gt_stats.h"

View File

@@ -8,9 +8,7 @@
#include <linux/device.h>
#include <linux/slab.h>
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_device_types.h"
#include "xe_hw_engine.h"
#include "xe_macros.h"
#include "xe_map.h"
@@ -108,22 +106,6 @@ void xe_hw_fence_irq_run(struct xe_hw_fence_irq *irq)
irq_work_queue(&irq->work);
}
void xe_hw_fence_irq_stop(struct xe_hw_fence_irq *irq)
{
spin_lock_irq(&irq->lock);
irq->enabled = false;
spin_unlock_irq(&irq->lock);
}
void xe_hw_fence_irq_start(struct xe_hw_fence_irq *irq)
{
spin_lock_irq(&irq->lock);
irq->enabled = true;
spin_unlock_irq(&irq->lock);
irq_work_queue(&irq->work);
}
void xe_hw_fence_ctx_init(struct xe_hw_fence_ctx *ctx, struct xe_gt *gt,
struct xe_hw_fence_irq *irq, const char *name)
{

View File

@@ -17,8 +17,6 @@ void xe_hw_fence_module_exit(void);
void xe_hw_fence_irq_init(struct xe_hw_fence_irq *irq);
void xe_hw_fence_irq_finish(struct xe_hw_fence_irq *irq);
void xe_hw_fence_irq_run(struct xe_hw_fence_irq *irq);
void xe_hw_fence_irq_stop(struct xe_hw_fence_irq *irq);
void xe_hw_fence_irq_start(struct xe_hw_fence_irq *irq);
void xe_hw_fence_ctx_init(struct xe_hw_fence_ctx *ctx, struct xe_gt *gt,
struct xe_hw_fence_irq *irq, const char *name);

View File

@@ -39,10 +39,16 @@ enum xe_hwmon_reg_operation {
REG_READ64,
};
#define MAX_VRAM_CHANNELS (16)
enum xe_hwmon_channel {
CHANNEL_CARD,
CHANNEL_PKG,
CHANNEL_VRAM,
CHANNEL_MCTRL,
CHANNEL_PCIE,
CHANNEL_VRAM_N,
CHANNEL_VRAM_N_MAX = CHANNEL_VRAM_N + MAX_VRAM_CHANNELS,
CHANNEL_MAX,
};
@@ -53,6 +59,15 @@ enum xe_fan_channel {
FAN_MAX,
};
enum xe_temp_limit {
TEMP_LIMIT_PKG_SHUTDOWN,
TEMP_LIMIT_PKG_CRIT,
TEMP_LIMIT_MEM_SHUTDOWN,
TEMP_LIMIT_PKG_MAX,
TEMP_LIMIT_MEM_CRIT,
TEMP_LIMIT_MAX
};
/* Attribute index for powerX_xxx_interval sysfs entries */
enum sensor_attr_power {
SENSOR_INDEX_PSYS_PL1,
@@ -91,6 +106,12 @@ enum sensor_attr_power {
*/
#define PL_WRITE_MBX_TIMEOUT_MS (1)
/* Index of memory controller in READ_THERMAL_DATA output */
#define TEMP_INDEX_MCTRL 2
/* Maximum characters in hwmon label name */
#define MAX_LABEL_SIZE 16
/**
* struct xe_hwmon_energy_info - to accumulate energy
*/
@@ -111,6 +132,24 @@ struct xe_hwmon_fan_info {
u64 time_prev;
};
/**
* struct xe_hwmon_thermal_info - to store temperature data
*/
struct xe_hwmon_thermal_info {
union {
/** @limit: temperatures limits */
u8 limit[TEMP_LIMIT_MAX];
/** @data: temperature limits in dwords */
u32 data[DIV_ROUND_UP(TEMP_LIMIT_MAX, sizeof(u32))];
};
/** @count: no of temperature sensors available for the platform */
u8 count;
/** @value: signed value from each sensor */
s8 value[U8_MAX];
/** @vram_label: vram label names */
char vram_label[MAX_VRAM_CHANNELS][MAX_LABEL_SIZE];
};
/**
* struct xe_hwmon - xe hwmon data structure
*/
@@ -137,7 +176,8 @@ struct xe_hwmon {
u32 pl1_on_boot[CHANNEL_MAX];
/** @pl2_on_boot: power limit PL2 on boot */
u32 pl2_on_boot[CHANNEL_MAX];
/** @temp: Temperature info */
struct xe_hwmon_thermal_info temp;
};
static int xe_hwmon_pcode_read_power_limit(const struct xe_hwmon *hwmon, u32 attr, int channel,
@@ -224,6 +264,8 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg
return BMG_PACKAGE_TEMPERATURE;
else if (channel == CHANNEL_VRAM)
return BMG_VRAM_TEMPERATURE;
else if (in_range(channel, CHANNEL_VRAM_N, CHANNEL_VRAM_N_MAX))
return BMG_VRAM_TEMPERATURE_N(channel - CHANNEL_VRAM_N);
} else if (xe->info.platform == XE_DG2) {
if (channel == CHANNEL_PKG)
return PCU_CR_PACKAGE_TEMPERATURE;
@@ -677,8 +719,29 @@ static const struct attribute_group *hwmon_groups[] = {
};
static const struct hwmon_channel_info * const hwmon_info[] = {
HWMON_CHANNEL_INFO(temp, HWMON_T_LABEL, HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(temp,
HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL |
HWMON_T_MAX,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL,
HWMON_T_CRIT | HWMON_T_EMERGENCY | HWMON_T_INPUT | HWMON_T_LABEL),
HWMON_CHANNEL_INFO(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL | HWMON_P_CRIT |
HWMON_P_CAP,
HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL | HWMON_P_CAP),
@@ -689,6 +752,75 @@ static const struct hwmon_channel_info * const hwmon_info[] = {
NULL
};
static int xe_hwmon_pcode_read_thermal_info(struct xe_hwmon *hwmon)
{
struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
u32 config = 0;
int ret;
ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_THERMAL_INFO, READ_THERMAL_LIMITS, 0),
&hwmon->temp.data[0], &hwmon->temp.data[1]);
if (ret)
return ret;
drm_dbg(&hwmon->xe->drm, "thermal info read val 0x%x val1 0x%x\n",
hwmon->temp.data[0], hwmon->temp.data[1]);
ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_THERMAL_INFO, READ_THERMAL_CONFIG, 0),
&config, NULL);
if (ret)
return ret;
drm_dbg(&hwmon->xe->drm, "thermal config count 0x%x\n", config);
hwmon->temp.count = REG_FIELD_GET(TEMP_MASK, config);
return ret;
}
static int get_mc_temp(struct xe_hwmon *hwmon, long *val)
{
struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
u32 *dword = (u32 *)hwmon->temp.value;
s32 average = 0;
int ret, i;
for (i = 0; i < DIV_ROUND_UP(TEMP_LIMIT_MAX, sizeof(u32)); i++) {
ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_THERMAL_INFO, READ_THERMAL_DATA, i),
(dword + i), NULL);
if (ret)
return ret;
drm_dbg(&hwmon->xe->drm, "thermal data for group %d val 0x%x\n", i, dword[i]);
}
for (i = TEMP_INDEX_MCTRL; i < hwmon->temp.count - 1; i++)
average += hwmon->temp.value[i];
average /= (hwmon->temp.count - TEMP_INDEX_MCTRL - 1);
*val = average * MILLIDEGREE_PER_DEGREE;
return 0;
}
static int get_pcie_temp(struct xe_hwmon *hwmon, long *val)
{
struct xe_tile *root_tile = xe_device_get_root_tile(hwmon->xe);
u32 data = 0;
int ret;
ret = xe_pcode_read(root_tile, PCODE_MBOX(PCODE_THERMAL_INFO, READ_THERMAL_DATA,
PCIE_SENSOR_GROUP_ID), &data, NULL);
if (ret)
return ret;
/* Sensor offset is different for G21 */
if (hwmon->xe->info.subplatform != XE_SUBPLATFORM_BATTLEMAGE_G21)
data = REG_FIELD_GET(PCIE_SENSOR_MASK, data);
data = REG_FIELD_GET(TEMP_MASK, data);
*val = (s8)data * MILLIDEGREE_PER_DEGREE;
return 0;
}
/* I1 is exposed as power_crit or as curr_crit depending on bit 31 */
static int xe_hwmon_pcode_read_i1(const struct xe_hwmon *hwmon, u32 *uval)
{
@@ -783,13 +915,77 @@ static void xe_hwmon_get_voltage(struct xe_hwmon *hwmon, int channel, long *valu
*value = DIV_ROUND_CLOSEST(REG_FIELD_GET(VOLTAGE_MASK, reg_val) * 2500, SF_VOLTAGE);
}
static inline bool is_vram_ch_available(struct xe_hwmon *hwmon, int channel)
{
struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe);
int vram_id = channel - CHANNEL_VRAM_N;
struct xe_reg vram_reg;
vram_reg = xe_hwmon_get_reg(hwmon, REG_TEMP, channel);
if (!xe_reg_is_valid(vram_reg) || !xe_mmio_read32(mmio, vram_reg))
return false;
/* Create label only for available vram channel */
sprintf(hwmon->temp.vram_label[vram_id], "vram_ch_%d", vram_id);
return true;
}
static umode_t
xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel)
{
switch (attr) {
case hwmon_temp_emergency:
switch (channel) {
case CHANNEL_PKG:
return hwmon->temp.limit[TEMP_LIMIT_PKG_SHUTDOWN] ? 0444 : 0;
case CHANNEL_VRAM:
return hwmon->temp.limit[TEMP_LIMIT_MEM_SHUTDOWN] ? 0444 : 0;
case CHANNEL_MCTRL:
case CHANNEL_PCIE:
return hwmon->temp.count ? 0444 : 0;
case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX:
return (is_vram_ch_available(hwmon, channel) &&
hwmon->temp.limit[TEMP_LIMIT_MEM_SHUTDOWN]) ? 0444 : 0;
default:
return 0;
}
case hwmon_temp_crit:
switch (channel) {
case CHANNEL_PKG:
return hwmon->temp.limit[TEMP_LIMIT_PKG_CRIT] ? 0444 : 0;
case CHANNEL_VRAM:
return hwmon->temp.limit[TEMP_LIMIT_MEM_CRIT] ? 0444 : 0;
case CHANNEL_MCTRL:
case CHANNEL_PCIE:
return hwmon->temp.count ? 0444 : 0;
case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX:
return (is_vram_ch_available(hwmon, channel) &&
hwmon->temp.limit[TEMP_LIMIT_MEM_CRIT]) ? 0444 : 0;
default:
return 0;
}
case hwmon_temp_max:
switch (channel) {
case CHANNEL_PKG:
return hwmon->temp.limit[TEMP_LIMIT_PKG_MAX] ? 0444 : 0;
default:
return 0;
}
case hwmon_temp_input:
case hwmon_temp_label:
return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_TEMP, channel)) ? 0444 : 0;
switch (channel) {
case CHANNEL_PKG:
case CHANNEL_VRAM:
return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_TEMP,
channel)) ? 0444 : 0;
case CHANNEL_MCTRL:
case CHANNEL_PCIE:
return hwmon->temp.count ? 0444 : 0;
case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX:
return is_vram_ch_available(hwmon, channel) ? 0444 : 0;
default:
return 0;
}
default:
return 0;
}
@@ -803,11 +999,67 @@ xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val)
switch (attr) {
case hwmon_temp_input:
reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_TEMP, channel));
switch (channel) {
case CHANNEL_PKG:
case CHANNEL_VRAM:
reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_TEMP, channel));
/* HW register value is in degrees Celsius, convert to millidegrees. */
*val = REG_FIELD_GET(TEMP_MASK, reg_val) * MILLIDEGREE_PER_DEGREE;
return 0;
/* HW register value is in degrees Celsius, convert to millidegrees. */
*val = REG_FIELD_GET(TEMP_MASK, reg_val) * MILLIDEGREE_PER_DEGREE;
return 0;
case CHANNEL_MCTRL:
return get_mc_temp(hwmon, val);
case CHANNEL_PCIE:
return get_pcie_temp(hwmon, val);
case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX:
reg_val = xe_mmio_read32(mmio, xe_hwmon_get_reg(hwmon, REG_TEMP, channel));
/*
* This temperature format is 24 bit [31:8] signed integer and 8 bit
* [7:0] fraction.
*/
*val = (s32)(REG_FIELD_GET(TEMP_MASK_VRAM_N, reg_val)) *
(REG_FIELD_GET(TEMP_SIGN_MASK, reg_val) ? -1 : 1) *
MILLIDEGREE_PER_DEGREE;
return 0;
default:
return -EOPNOTSUPP;
}
case hwmon_temp_emergency:
switch (channel) {
case CHANNEL_PKG:
case CHANNEL_MCTRL:
case CHANNEL_PCIE:
*val = hwmon->temp.limit[TEMP_LIMIT_PKG_SHUTDOWN] * MILLIDEGREE_PER_DEGREE;
return 0;
case CHANNEL_VRAM:
case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX:
*val = hwmon->temp.limit[TEMP_LIMIT_MEM_SHUTDOWN] * MILLIDEGREE_PER_DEGREE;
return 0;
default:
return -EOPNOTSUPP;
}
case hwmon_temp_crit:
switch (channel) {
case CHANNEL_PKG:
case CHANNEL_MCTRL:
case CHANNEL_PCIE:
*val = hwmon->temp.limit[TEMP_LIMIT_PKG_CRIT] * MILLIDEGREE_PER_DEGREE;
return 0;
case CHANNEL_VRAM:
case CHANNEL_VRAM_N...CHANNEL_VRAM_N_MAX:
*val = hwmon->temp.limit[TEMP_LIMIT_MEM_CRIT] * MILLIDEGREE_PER_DEGREE;
return 0;
default:
return -EOPNOTSUPP;
}
case hwmon_temp_max:
switch (channel) {
case CHANNEL_PKG:
*val = hwmon->temp.limit[TEMP_LIMIT_PKG_MAX] * MILLIDEGREE_PER_DEGREE;
return 0;
default:
return -EOPNOTSUPP;
}
default:
return -EOPNOTSUPP;
}
@@ -1163,12 +1415,20 @@ static int xe_hwmon_read_label(struct device *dev,
enum hwmon_sensor_types type,
u32 attr, int channel, const char **str)
{
struct xe_hwmon *hwmon = dev_get_drvdata(dev);
switch (type) {
case hwmon_temp:
if (channel == CHANNEL_PKG)
*str = "pkg";
else if (channel == CHANNEL_VRAM)
*str = "vram";
else if (channel == CHANNEL_MCTRL)
*str = "mctrl";
else if (channel == CHANNEL_PCIE)
*str = "pcie";
else if (in_range(channel, CHANNEL_VRAM_N, CHANNEL_VRAM_N_MAX))
*str = hwmon->temp.vram_label[channel - CHANNEL_VRAM_N];
return 0;
case hwmon_power:
case hwmon_energy:
@@ -1263,6 +1523,9 @@ xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon)
for (channel = 0; channel < FAN_MAX; channel++)
if (xe_hwmon_is_visible(hwmon, hwmon_fan, hwmon_fan_input, channel))
xe_hwmon_fan_input_read(hwmon, channel, &fan_speed);
if (hwmon->xe->info.has_mbx_thermal_info && xe_hwmon_pcode_read_thermal_info(hwmon))
drm_warn(&hwmon->xe->drm, "Thermal mailbox not supported by card firmware\n");
}
int xe_hwmon_register(struct xe_device *xe)

View File

@@ -5,6 +5,7 @@
* Copyright (C) 2025 Intel Corporation.
*/
#include <drm/drm_print.h>
#include <linux/array_size.h>
#include <linux/container_of.h>
#include <linux/device.h>
@@ -26,11 +27,11 @@
#include "regs/xe_i2c_regs.h"
#include "regs/xe_irq_regs.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_i2c.h"
#include "xe_mmio.h"
#include "xe_platform_types.h"
#include "xe_sriov.h"
#include "xe_survivability_mode.h"
/**
* DOC: Xe I2C devices
@@ -213,11 +214,13 @@ static const struct irq_domain_ops xe_i2c_irq_ops = {
.map = xe_i2c_irq_map,
};
static int xe_i2c_create_irq(struct xe_i2c *i2c)
static int xe_i2c_create_irq(struct xe_device *xe)
{
struct xe_i2c *i2c = xe->i2c;
struct irq_domain *domain;
if (!(i2c->ep.capabilities & XE_I2C_EP_CAP_IRQ))
if (!(i2c->ep.capabilities & XE_I2C_EP_CAP_IRQ) ||
xe_survivability_mode_is_boot_enabled(xe))
return 0;
domain = irq_domain_create_linear(dev_fwnode(i2c->drm_dev), 1, &xe_i2c_irq_ops, NULL);
@@ -351,7 +354,7 @@ int xe_i2c_probe(struct xe_device *xe)
if (ret)
return ret;
ret = xe_i2c_create_irq(i2c);
ret = xe_i2c_create_irq(xe);
if (ret)
goto err_unregister_notifier;

View File

@@ -10,7 +10,6 @@
#include <drm/drm_managed.h>
#include "display/xe_display.h"
#include "regs/xe_guc_regs.h"
#include "regs/xe_irq_regs.h"
#include "xe_device.h"
#include "xe_drv.h"

View File

@@ -15,10 +15,12 @@
#define XE_LB_MAX_PAYLOAD_SIZE SZ_4K
/**
* xe_late_bind_fw_id - enum to determine late binding fw index
* enum xe_late_bind_fw_id - enum to determine late binding fw index
*/
enum xe_late_bind_fw_id {
/** @XE_LB_FW_FAN_CONTROL: Fan control */
XE_LB_FW_FAN_CONTROL = 0,
/** @XE_LB_FW_MAX_ID: Number of IDs */
XE_LB_FW_MAX_ID
};

View File

@@ -289,7 +289,7 @@ void xe_lmtt_invalidate_hw(struct xe_lmtt *lmtt)
ERR_PTR(err));
if (xe_device_has_mert(xe) && xe_tile_is_root(tile)) {
err = xe_mert_invalidate_lmtt(tile);
err = xe_mert_invalidate_lmtt(xe);
if (err)
xe_tile_sriov_err(tile, "MERT LMTT invalidation failed (%pe)",
ERR_PTR(err));

View File

@@ -857,7 +857,7 @@ u32 xe_lrc_ctx_timestamp_udw_ggtt_addr(struct xe_lrc *lrc)
*
* Returns: ctx timestamp value
*/
u64 xe_lrc_ctx_timestamp(struct xe_lrc *lrc)
static u64 xe_lrc_ctx_timestamp(struct xe_lrc *lrc)
{
struct xe_device *xe = lrc_to_xe(lrc);
struct iosys_map map;
@@ -1068,6 +1068,9 @@ static ssize_t setup_utilization_wa(struct xe_lrc *lrc,
{
u32 *cmd = batch;
if (IS_SRIOV_VF(gt_to_xe(lrc->gt)))
return 0;
if (xe_gt_WARN_ON(lrc->gt, max_len < 12))
return -ENOSPC;
@@ -2406,35 +2409,31 @@ static int get_ctx_timestamp(struct xe_lrc *lrc, u32 engine_id, u64 *reg_ctx_ts)
}
/**
* xe_lrc_update_timestamp() - Update ctx timestamp
* xe_lrc_timestamp() - Current ctx timestamp
* @lrc: Pointer to the lrc.
* @old_ts: Old timestamp value
*
* Populate @old_ts current saved ctx timestamp, read new ctx timestamp and
* update saved value. With support for active contexts, the calculation may be
* slightly racy, so follow a read-again logic to ensure that the context is
* still active before returning the right timestamp.
* Return latest ctx timestamp. With support for active contexts, the
* calculation may bb slightly racy, so follow a read-again logic to ensure that
* the context is still active before returning the right timestamp.
*
* Returns: New ctx timestamp value
*/
u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts)
u64 xe_lrc_timestamp(struct xe_lrc *lrc)
{
u64 lrc_ts, reg_ts;
u64 lrc_ts, reg_ts, new_ts;
u32 engine_id;
*old_ts = lrc->ctx_timestamp;
lrc_ts = xe_lrc_ctx_timestamp(lrc);
/* CTX_TIMESTAMP mmio read is invalid on VF, so return the LRC value */
if (IS_SRIOV_VF(lrc_to_xe(lrc))) {
lrc->ctx_timestamp = lrc_ts;
new_ts = lrc_ts;
goto done;
}
if (lrc_ts == CONTEXT_ACTIVE) {
engine_id = xe_lrc_engine_id(lrc);
if (!get_ctx_timestamp(lrc, engine_id, &reg_ts))
lrc->ctx_timestamp = reg_ts;
new_ts = reg_ts;
/* read lrc again to ensure context is still active */
lrc_ts = xe_lrc_ctx_timestamp(lrc);
@@ -2445,9 +2444,27 @@ u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts)
* be a separate if condition.
*/
if (lrc_ts != CONTEXT_ACTIVE)
lrc->ctx_timestamp = lrc_ts;
new_ts = lrc_ts;
done:
return new_ts;
}
/**
* xe_lrc_update_timestamp() - Update ctx timestamp
* @lrc: Pointer to the lrc.
* @old_ts: Old timestamp value
*
* Populate @old_ts current saved ctx timestamp, read new ctx timestamp and
* update saved value.
*
* Returns: New ctx timestamp value
*/
u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts)
{
*old_ts = lrc->ctx_timestamp;
lrc->ctx_timestamp = xe_lrc_timestamp(lrc);
trace_xe_lrc_update_timestamp(lrc, *old_ts);
return lrc->ctx_timestamp;

View File

@@ -145,7 +145,6 @@ void xe_lrc_snapshot_free(struct xe_lrc_snapshot *snapshot);
u32 xe_lrc_ctx_timestamp_ggtt_addr(struct xe_lrc *lrc);
u32 xe_lrc_ctx_timestamp_udw_ggtt_addr(struct xe_lrc *lrc);
u64 xe_lrc_ctx_timestamp(struct xe_lrc *lrc);
u32 xe_lrc_ctx_job_timestamp_ggtt_addr(struct xe_lrc *lrc);
u32 xe_lrc_ctx_job_timestamp(struct xe_lrc *lrc);
int xe_lrc_setup_wa_bb_with_scratch(struct xe_lrc *lrc, struct xe_hw_engine *hwe,
@@ -165,4 +164,6 @@ int xe_lrc_setup_wa_bb_with_scratch(struct xe_lrc *lrc, struct xe_hw_engine *hwe
*/
u64 xe_lrc_update_timestamp(struct xe_lrc *lrc, u64 *old_ts);
u64 xe_lrc_timestamp(struct xe_lrc *lrc);
#endif

View File

@@ -7,7 +7,6 @@
#include "regs/xe_guc_regs.h"
#include "regs/xe_irq_regs.h"
#include "regs/xe_regs.h"
#include "xe_assert.h"
#include "xe_bo.h"
@@ -16,7 +15,6 @@
#include "xe_gt.h"
#include "xe_guc.h"
#include "xe_hw_engine.h"
#include "xe_map.h"
#include "xe_memirq.h"
#include "xe_tile_printk.h"

View File

@@ -9,25 +9,38 @@
#include "xe_device.h"
#include "xe_mert.h"
#include "xe_mmio.h"
#include "xe_sriov_printk.h"
#include "xe_tile.h"
/**
* xe_mert_invalidate_lmtt - Invalidate MERT LMTT
* @tile: the &xe_tile
* xe_mert_init_early() - Initialize MERT data
* @xe: the &xe_device with MERT to init
*/
void xe_mert_init_early(struct xe_device *xe)
{
struct xe_tile *tile = xe_device_get_root_tile(xe);
struct xe_mert *mert = &tile->mert;
spin_lock_init(&mert->lock);
init_completion(&mert->tlb_inv_done);
}
/**
* xe_mert_invalidate_lmtt() - Invalidate MERT LMTT
* @xe: the &xe_device with MERT
*
* Trigger invalidation of the MERT LMTT and wait for completion.
*
* Return: 0 on success or -ETIMEDOUT in case of a timeout.
*/
int xe_mert_invalidate_lmtt(struct xe_tile *tile)
int xe_mert_invalidate_lmtt(struct xe_device *xe)
{
struct xe_device *xe = tile_to_xe(tile);
struct xe_tile *tile = xe_device_get_root_tile(xe);
struct xe_mert *mert = &tile->mert;
const long timeout = HZ / 4;
unsigned long flags;
xe_assert(xe, xe_device_has_mert(xe));
xe_assert(xe, xe_tile_is_root(tile));
spin_lock_irqsave(&mert->lock, flags);
if (!mert->tlb_inv_triggered) {
@@ -43,6 +56,37 @@ int xe_mert_invalidate_lmtt(struct xe_tile *tile)
return 0;
}
static void mert_handle_cat_error(struct xe_device *xe)
{
struct xe_tile *tile = xe_device_get_root_tile(xe);
u32 reg_val, vfid, code;
reg_val = xe_mmio_read32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT);
if (!reg_val)
return;
xe_mmio_write32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT, 0);
vfid = FIELD_GET(CATERR_VFID, reg_val);
code = FIELD_GET(CATERR_CODES, reg_val);
switch (code) {
case CATERR_NO_ERROR:
break;
case CATERR_UNMAPPED_GGTT:
xe_sriov_err(xe, "MERT: CAT_ERR: Access to an unmapped GGTT!\n");
xe_device_declare_wedged(xe);
break;
case CATERR_LMTT_FAULT:
xe_sriov_dbg(xe, "MERT: CAT_ERR: VF%u LMTT fault!\n", vfid);
/* XXX: track/report malicious VF activity */
break;
default:
xe_sriov_err(xe, "MERT: Unexpected CAT_ERR code=%#x!\n", code);
xe_device_declare_wedged(xe);
break;
}
}
/**
* xe_mert_irq_handler - Handler for MERT interrupts
* @xe: the &xe_device
@@ -53,30 +97,22 @@ int xe_mert_invalidate_lmtt(struct xe_tile *tile)
void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl)
{
struct xe_tile *tile = xe_device_get_root_tile(xe);
struct xe_mert *mert = &tile->mert;
unsigned long flags;
u32 reg_val;
u8 err;
if (!(master_ctl & SOC_H2DMEMINT_IRQ))
return;
reg_val = xe_mmio_read32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT);
xe_mmio_write32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT, 0);
mert_handle_cat_error(xe);
err = FIELD_GET(MERT_TLB_CT_ERROR_MASK, reg_val);
if (err == MERT_TLB_CT_LMTT_FAULT)
drm_dbg(&xe->drm, "MERT catastrophic error: LMTT fault (VF%u)\n",
FIELD_GET(MERT_TLB_CT_VFID_MASK, reg_val));
else if (err)
drm_dbg(&xe->drm, "MERT catastrophic error: Unexpected fault (0x%x)\n", err);
spin_lock_irqsave(&tile->mert.lock, flags);
if (tile->mert.tlb_inv_triggered) {
spin_lock_irqsave(&mert->lock, flags);
if (mert->tlb_inv_triggered) {
reg_val = xe_mmio_read32(&tile->mmio, MERT_TLB_INV_DESC_A);
if (!(reg_val & MERT_TLB_INV_DESC_A_VALID)) {
tile->mert.tlb_inv_triggered = false;
complete_all(&tile->mert.tlb_inv_done);
mert->tlb_inv_triggered = false;
complete_all(&mert->tlb_inv_done);
}
}
spin_unlock_irqrestore(&tile->mert.lock, flags);
spin_unlock_irqrestore(&mert->lock, flags);
}

View File

@@ -3,30 +3,33 @@
* Copyright(c) 2025, Intel Corporation. All rights reserved.
*/
#ifndef __XE_MERT_H__
#define __XE_MERT_H__
#ifndef _XE_MERT_H_
#define _XE_MERT_H_
#include <linux/completion.h>
#include <linux/spinlock.h>
#include <linux/types.h>
struct xe_device;
struct xe_tile;
/**
* struct xe_mert - MERT related data
*/
struct xe_mert {
/** @lock: protects the TLB invalidation status */
spinlock_t lock;
/** @tlb_inv_triggered: indicates if TLB invalidation was triggered */
bool tlb_inv_triggered;
/** @mert.tlb_inv_done: completion of TLB invalidation */
/** @tlb_inv_done: completion of TLB invalidation */
struct completion tlb_inv_done;
};
#ifdef CONFIG_PCI_IOV
int xe_mert_invalidate_lmtt(struct xe_tile *tile);
void xe_mert_init_early(struct xe_device *xe);
int xe_mert_invalidate_lmtt(struct xe_device *xe);
void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl);
#else
static inline void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl) { }
#endif
#endif /* __XE_MERT_H__ */
#endif

View File

@@ -14,12 +14,8 @@
#include <drm/drm_print.h>
#include "regs/xe_bars.h"
#include "regs/xe_regs.h"
#include "xe_device.h"
#include "xe_gt.h"
#include "xe_gt_printk.h"
#include "xe_gt_sriov_vf.h"
#include "xe_macros.h"
#include "xe_sriov.h"
#include "xe_trace.h"
#include "xe_wa.h"

View File

@@ -6,7 +6,6 @@
#include "xe_mocs.h"
#include "regs/xe_gt_regs.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_exec_queue.h"
#include "xe_force_wake.h"
@@ -17,7 +16,6 @@
#include "xe_platform_types.h"
#include "xe_pm.h"
#include "xe_sriov.h"
#include "xe_step_types.h"
#if IS_ENABLED(CONFIG_DRM_XE_DEBUG)
#define mocs_dbg xe_gt_dbg

View File

@@ -10,6 +10,7 @@
#include <drm/drm_module.h>
#include "xe_device_types.h"
#include "xe_drv.h"
#include "xe_configfs.h"
#include "xe_hw_fence.h"
@@ -29,7 +30,8 @@
#define DEFAULT_FORCE_PROBE CONFIG_DRM_XE_FORCE_PROBE
#define DEFAULT_MAX_VFS ~0
#define DEFAULT_MAX_VFS_STR "unlimited"
#define DEFAULT_WEDGED_MODE 1
#define DEFAULT_WEDGED_MODE XE_WEDGED_MODE_DEFAULT
#define DEFAULT_WEDGED_MODE_STR XE_WEDGED_MODE_DEFAULT_STR
#define DEFAULT_SVM_NOTIFIER_SIZE 512
struct xe_modparam xe_modparam = {
@@ -88,10 +90,10 @@ MODULE_PARM_DESC(max_vfs,
"[default=" DEFAULT_MAX_VFS_STR "])");
#endif
module_param_named_unsafe(wedged_mode, xe_modparam.wedged_mode, int, 0600);
module_param_named_unsafe(wedged_mode, xe_modparam.wedged_mode, uint, 0600);
MODULE_PARM_DESC(wedged_mode,
"Module's default policy for the wedged mode (0=never, 1=upon-critical-errors, 2=upon-any-hang "
"[default=" __stringify(DEFAULT_WEDGED_MODE) "])");
"Module's default policy for the wedged mode (0=never, 1=upon-critical-error, 2=upon-any-hang-no-reset "
"[default=" DEFAULT_WEDGED_MODE_STR "])");
static int xe_check_nomodeset(void)
{

View File

@@ -21,7 +21,7 @@ struct xe_modparam {
#ifdef CONFIG_PCI_IOV
unsigned int max_vfs;
#endif
int wedged_mode;
unsigned int wedged_mode;
u32 svm_notifier_size;
};

View File

@@ -6,7 +6,6 @@
#include <linux/intel_dg_nvm_aux.h>
#include <linux/pci.h>
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_mmio.h"
#include "xe_nvm.h"

View File

@@ -10,14 +10,11 @@
#include "xe_page_reclaim.h"
#include "regs/xe_gt_regs.h"
#include "xe_assert.h"
#include "xe_gt_stats.h"
#include "xe_macros.h"
#include "xe_mmio.h"
#include "xe_pat.h"
#include "xe_sa.h"
#include "xe_tlb_inval_types.h"
#include "xe_vm.h"
/**
* xe_page_reclaim_skip() - Decide whether PRL should be skipped for a VMA
@@ -108,7 +105,6 @@ void xe_page_reclaim_list_invalidate(struct xe_page_reclaim_list *prl)
*/
void xe_page_reclaim_list_init(struct xe_page_reclaim_list *prl)
{
// xe_page_reclaim_list_invalidate(prl);
prl->entries = NULL;
prl->num_entries = 0;
}

View File

@@ -19,6 +19,7 @@
struct xe_tlb_inval;
struct xe_tlb_inval_fence;
struct xe_tile;
struct xe_gt;
struct xe_vma;
struct xe_guc_page_reclaim_entry {
@@ -75,6 +76,25 @@ struct drm_suballoc *xe_page_reclaim_create_prl_bo(struct xe_tlb_inval *tlb_inva
struct xe_page_reclaim_list *prl,
struct xe_tlb_inval_fence *fence);
void xe_page_reclaim_list_invalidate(struct xe_page_reclaim_list *prl);
/**
* xe_page_reclaim_list_abort() - Invalidate a PRL and log an abort reason
* @gt: GT owning the page reclaim request
* @prl: Page reclaim list to invalidate
* @fmt: format string for the log message with args
*
* Abort page reclaim process by invalidating PRL and doing any relevant logging.
*/
#define xe_page_reclaim_list_abort(gt, prl, fmt, ...) \
do { \
struct xe_gt *__gt = (gt); \
struct xe_page_reclaim_list *__prl = (prl); \
\
xe_page_reclaim_list_invalidate(__prl); \
xe_gt_stats_incr(__gt, XE_GT_STATS_ID_PRL_ABORTED_COUNT, 1); \
vm_dbg(&gt_to_xe(__gt)->drm, "PRL aborted: " fmt, ##__VA_ARGS__); \
} while (0)
void xe_page_reclaim_list_init(struct xe_page_reclaim_list *prl);
int xe_page_reclaim_list_alloc_entries(struct xe_page_reclaim_list *prl);
/**

View File

@@ -132,9 +132,10 @@ static const struct xe_pat_table_entry xelpg_pat_table[] = {
* in the table.
*
* Note: There is an implicit assumption in the driver that compression and
* coh_1way+ are mutually exclusive. If this is ever not true then userptr
* and imported dma-buf from external device will have uncleared ccs state. See
* also xe_bo_needs_ccs_pages().
* coh_1way+ are mutually exclusive for platforms prior to Xe3. Starting
* with Xe3, compression can be combined with coherency. If using compression
* with coherency, userptr and imported dma-buf from external device will
* have uncleared ccs state. See also xe_bo_needs_ccs_pages().
*/
#define XE2_PAT(no_promote, comp_en, l3clos, l3_policy, l4_policy, __coh_mode) \
{ \
@@ -144,8 +145,7 @@ static const struct xe_pat_table_entry xelpg_pat_table[] = {
REG_FIELD_PREP(XE2_L3_POLICY, l3_policy) | \
REG_FIELD_PREP(XE2_L4_POLICY, l4_policy) | \
REG_FIELD_PREP(XE2_COH_MODE, __coh_mode), \
.coh_mode = (BUILD_BUG_ON_ZERO(__coh_mode && comp_en) || __coh_mode) ? \
XE_COH_AT_LEAST_1WAY : XE_COH_NONE, \
.coh_mode = __coh_mode ? XE_COH_AT_LEAST_1WAY : XE_COH_NONE, \
.valid = 1 \
}
@@ -181,6 +181,38 @@ static const struct xe_pat_table_entry xe2_pat_table[] = {
[31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ),
};
static const struct xe_pat_table_entry xe3_lpg_pat_table[] = {
[ 0] = XE2_PAT( 0, 0, 0, 0, 3, 0 ),
[ 1] = XE2_PAT( 0, 0, 0, 0, 3, 2 ),
[ 2] = XE2_PAT( 0, 0, 0, 0, 3, 3 ),
[ 3] = XE2_PAT( 0, 0, 0, 3, 3, 0 ),
[ 4] = XE2_PAT( 0, 0, 0, 3, 0, 2 ),
[ 5] = XE2_PAT( 0, 0, 0, 3, 3, 2 ),
[ 6] = XE2_PAT( 1, 0, 0, 1, 3, 0 ),
[ 7] = XE2_PAT( 0, 0, 0, 3, 0, 3 ),
[ 8] = XE2_PAT( 0, 0, 0, 3, 0, 0 ),
[ 9] = XE2_PAT( 0, 1, 0, 0, 3, 0 ),
[10] = XE2_PAT( 0, 1, 0, 3, 0, 0 ),
[11] = XE2_PAT( 1, 1, 0, 1, 3, 0 ),
[12] = XE2_PAT( 0, 1, 0, 3, 3, 0 ),
[13] = XE2_PAT( 0, 0, 0, 0, 0, 0 ),
[14] = XE2_PAT( 0, 1, 0, 0, 0, 0 ),
[15] = XE2_PAT( 1, 1, 0, 1, 1, 0 ),
[16] = XE2_PAT( 0, 1, 0, 0, 3, 2 ),
/* 17..19 are reserved; leave set to all 0's */
[20] = XE2_PAT( 0, 0, 1, 0, 3, 0 ),
[21] = XE2_PAT( 0, 1, 1, 0, 3, 0 ),
[22] = XE2_PAT( 0, 0, 1, 0, 3, 2 ),
[23] = XE2_PAT( 0, 0, 1, 0, 3, 3 ),
[24] = XE2_PAT( 0, 0, 2, 0, 3, 0 ),
[25] = XE2_PAT( 0, 1, 2, 0, 3, 0 ),
[26] = XE2_PAT( 0, 0, 2, 0, 3, 2 ),
[27] = XE2_PAT( 0, 0, 2, 0, 3, 3 ),
[28] = XE2_PAT( 0, 0, 3, 0, 3, 0 ),
[29] = XE2_PAT( 0, 1, 3, 0, 3, 0 ),
[30] = XE2_PAT( 0, 0, 3, 0, 3, 2 ),
[31] = XE2_PAT( 0, 0, 3, 0, 3, 3 ),
};
/* Special PAT values programmed outside the main table */
static const struct xe_pat_table_entry xe2_pat_ats = XE2_PAT( 0, 0, 0, 0, 3, 3 );
static const struct xe_pat_table_entry xe2_pat_pta = XE2_PAT( 0, 0, 0, 0, 3, 0 );
@@ -490,6 +522,7 @@ static const struct xe_pat_ops xe3p_xpc_pat_ops = {
void xe_pat_init_early(struct xe_device *xe)
{
xe->pat.idx[XE_CACHE_WB_COMPRESSION] = XE_PAT_INVALID_IDX;
if (GRAPHICS_VERx100(xe) == 3511) {
xe->pat.ops = &xe3p_xpc_pat_ops;
xe->pat.table = xe3p_xpc_pat_table;
@@ -501,7 +534,12 @@ void xe_pat_init_early(struct xe_device *xe)
xe->pat.idx[XE_CACHE_WB] = 2;
} else if (GRAPHICS_VER(xe) == 30 || GRAPHICS_VER(xe) == 20) {
xe->pat.ops = &xe2_pat_ops;
xe->pat.table = xe2_pat_table;
if (GRAPHICS_VER(xe) == 30) {
xe->pat.table = xe3_lpg_pat_table;
xe->pat.idx[XE_CACHE_WB_COMPRESSION] = 16;
} else {
xe->pat.table = xe2_pat_table;
}
xe->pat.pat_ats = &xe2_pat_ats;
if (IS_DGFX(xe))
xe->pat.pat_pta = &xe2_pat_pta;
@@ -658,6 +696,8 @@ int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p)
if (GRAPHICS_VER(xe) >= 20) {
drm_printf(p, "IDX[XE_CACHE_NONE_COMPRESSION] = %d\n",
xe->pat.idx[XE_CACHE_NONE_COMPRESSION]);
drm_printf(p, "IDX[XE_CACHE_WB_COMPRESSION] = %d\n",
xe->pat.idx[XE_CACHE_WB_COMPRESSION]);
}
return 0;

View File

@@ -12,6 +12,8 @@ struct drm_printer;
struct xe_device;
struct xe_gt;
#define XE_PAT_INVALID_IDX U16_MAX
/**
* struct xe_pat_table_entry - The pat_index encoding and other meta information.
*/

View File

@@ -24,7 +24,6 @@
#include "xe_gt.h"
#include "xe_gt_sriov_vf.h"
#include "xe_guc.h"
#include "xe_macros.h"
#include "xe_mmio.h"
#include "xe_module.h"
#include "xe_pci_rebar.h"
@@ -366,6 +365,7 @@ static const struct xe_device_desc bmg_desc = {
.has_fan_control = true,
.has_flat_ccs = 1,
.has_mbx_power_limits = true,
.has_mbx_thermal_info = true,
.has_gsc_nvm = 1,
.has_heci_cscfi = 1,
.has_i2c = true,
@@ -392,6 +392,7 @@ static const struct xe_device_desc ptl_desc = {
.has_sriov = true,
.has_mem_copy_instr = true,
.has_pre_prod_wa = 1,
.has_pxp = true,
.max_gt_per_tile = 2,
.needs_scratch = true,
.needs_shared_vf_gt_wq = true,
@@ -421,6 +422,7 @@ static const struct xe_device_desc cri_desc = {
.has_gsc_nvm = 1,
.has_i2c = true,
.has_mbx_power_limits = true,
.has_mbx_thermal_info = true,
.has_mert = true,
.has_pre_prod_wa = 1,
.has_soc_remapper_sysctrl = true,
@@ -686,6 +688,7 @@ static int xe_info_init_early(struct xe_device *xe,
/* runtime fusing may force flat_ccs to disabled later */
xe->info.has_flat_ccs = desc->has_flat_ccs;
xe->info.has_mbx_power_limits = desc->has_mbx_power_limits;
xe->info.has_mbx_thermal_info = desc->has_mbx_thermal_info;
xe->info.has_gsc_nvm = desc->has_gsc_nvm;
xe->info.has_heci_gscfi = desc->has_heci_gscfi;
xe->info.has_heci_cscfi = desc->has_heci_cscfi;

View File

@@ -48,6 +48,7 @@ struct xe_device_desc {
u8 has_late_bind:1;
u8 has_llc:1;
u8 has_mbx_power_limits:1;
u8 has_mbx_thermal_info:1;
u8 has_mem_copy_instr:1;
u8 has_mert:1;
u8 has_pre_prod_wa:1;

View File

@@ -50,6 +50,13 @@
#define READ_PL_FROM_FW 0x1
#define READ_PL_FROM_PCODE 0x0
#define PCODE_THERMAL_INFO 0x25
#define READ_THERMAL_LIMITS 0x0
#define READ_THERMAL_CONFIG 0x1
#define READ_THERMAL_DATA 0x2
#define PCIE_SENSOR_GROUP_ID 0x2
#define PCIE_SENSOR_MASK REG_GENMASK(31, 16)
#define PCODE_LATE_BINDING 0x5C
#define GET_CAPABILITY_STATUS 0x0
#define V1_FAN_SUPPORTED REG_BIT(0)

View File

@@ -260,10 +260,19 @@ int xe_pm_resume(struct xe_device *xe)
xe_irq_resume(xe);
for_each_gt(gt, xe, id)
xe_gt_resume(gt);
for_each_gt(gt, xe, id) {
err = xe_gt_resume(gt);
if (err)
break;
}
/*
* Try to bring up display before bailing from GT resume failure,
* so we don't leave the user clueless with a blank screen.
*/
xe_display_pm_resume(xe);
if (err)
goto err;
err = xe_bo_restore_late(xe);
if (err)
@@ -656,10 +665,19 @@ int xe_pm_runtime_resume(struct xe_device *xe)
xe_irq_resume(xe);
for_each_gt(gt, xe, id)
xe->d3cold.allowed ? xe_gt_resume(gt) : xe_gt_runtime_resume(gt);
for_each_gt(gt, xe, id) {
err = xe->d3cold.allowed ? xe_gt_resume(gt) : xe_gt_runtime_resume(gt);
if (err)
break;
}
/*
* Try to bring up display before bailing from GT resume failure,
* so we don't leave the user clueless with a blank screen.
*/
xe_display_pm_runtime_resume(xe);
if (err)
goto out;
if (xe->d3cold.allowed) {
err = xe_bo_restore_late(xe);

View File

@@ -6,7 +6,7 @@
#include <linux/debugfs.h>
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_configfs.h"
#include "xe_psmi.h"

View File

@@ -11,6 +11,7 @@
#include "xe_drm_client.h"
#include "xe_exec_queue.h"
#include "xe_gt.h"
#include "xe_gt_stats.h"
#include "xe_migrate.h"
#include "xe_page_reclaim.h"
#include "xe_pt_types.h"
@@ -1576,12 +1577,6 @@ static bool xe_pt_check_kill(u64 addr, u64 next, unsigned int level,
return false;
}
/* Huge 2MB leaf lives directly in a level-1 table and has no children */
static bool is_2m_pte(struct xe_pt *pte)
{
return pte->level == 1 && !pte->base.children;
}
/* page_size = 2^(reclamation_size + XE_PTE_SHIFT) */
#define COMPUTE_RECLAIM_ADDRESS_MASK(page_size) \
({ \
@@ -1593,8 +1588,10 @@ static int generate_reclaim_entry(struct xe_tile *tile,
struct xe_page_reclaim_list *prl,
u64 pte, struct xe_pt *xe_child)
{
struct xe_gt *gt = tile->primary_gt;
struct xe_guc_page_reclaim_entry *reclaim_entries = prl->entries;
u64 phys_page = (pte & XE_PTE_ADDR_MASK) >> XE_PTE_SHIFT;
u64 phys_addr = pte & XE_PTE_ADDR_MASK;
u64 phys_page = phys_addr >> XE_PTE_SHIFT;
int num_entries = prl->num_entries;
u32 reclamation_size;
@@ -1612,16 +1609,21 @@ static int generate_reclaim_entry(struct xe_tile *tile,
* Only 4K, 64K (level 0), and 2M pages are supported by hardware for page reclaim
*/
if (xe_child->level == 0 && !(pte & XE_PTE_PS64)) {
xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_4K_ENTRY_COUNT, 1);
reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_4K); /* reclamation_size = 0 */
xe_tile_assert(tile, phys_addr % SZ_4K == 0);
} else if (xe_child->level == 0) {
xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_64K_ENTRY_COUNT, 1);
reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_64K); /* reclamation_size = 4 */
} else if (is_2m_pte(xe_child)) {
xe_tile_assert(tile, phys_addr % SZ_64K == 0);
} else if (xe_child->level == 1 && pte & XE_PDE_PS_2M) {
xe_gt_stats_incr(gt, XE_GT_STATS_ID_PRL_2M_ENTRY_COUNT, 1);
reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_2M); /* reclamation_size = 9 */
xe_tile_assert(tile, phys_addr % SZ_2M == 0);
} else {
xe_page_reclaim_list_invalidate(prl);
vm_dbg(&tile_to_xe(tile)->drm,
"PRL invalidate: unsupported PTE level=%u pte=%#llx\n",
xe_child->level, pte);
xe_page_reclaim_list_abort(tile->primary_gt, prl,
"unsupported PTE level=%u pte=%#llx",
xe_child->level, pte);
return -EINVAL;
}
@@ -1648,20 +1650,40 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
struct xe_pt_stage_unbind_walk *xe_walk =
container_of(walk, typeof(*xe_walk), base);
struct xe_device *xe = tile_to_xe(xe_walk->tile);
pgoff_t first = xe_pt_offset(addr, xe_child->level, walk);
bool killed;
XE_WARN_ON(!*child);
XE_WARN_ON(!level);
/* Check for leaf node */
if (xe_walk->prl && xe_page_reclaim_list_valid(xe_walk->prl) &&
!xe_child->base.children) {
(!xe_child->base.children || !xe_child->base.children[first])) {
struct iosys_map *leaf_map = &xe_child->bo->vmap;
pgoff_t first = xe_pt_offset(addr, 0, walk);
pgoff_t count = xe_pt_num_entries(addr, next, 0, walk);
pgoff_t count = xe_pt_num_entries(addr, next, xe_child->level, walk);
for (pgoff_t i = 0; i < count; i++) {
u64 pte = xe_map_rd(xe, leaf_map, (first + i) * sizeof(u64), u64);
int ret;
/*
* In rare scenarios, pte may not be written yet due to racy conditions.
* In such cases, invalidate the PRL and fallback to full PPC invalidation.
*/
if (!pte) {
xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl,
"found zero pte at addr=%#llx", addr);
break;
}
/* Ensure it is a defined page */
xe_tile_assert(xe_walk->tile,
xe_child->level == 0 ||
(pte & (XE_PTE_PS64 | XE_PDE_PS_2M | XE_PDPE_PS_1G)));
/* An entry should be added for 64KB but contigious 4K have XE_PTE_PS64 */
if (pte & XE_PTE_PS64)
i += 15; /* Skip other 15 consecutive 4K pages in the 64K page */
/* Account for NULL terminated entry on end (-1) */
if (xe_walk->prl->num_entries < XE_PAGE_RECLAIM_MAX_ENTRIES - 1) {
ret = generate_reclaim_entry(xe_walk->tile, xe_walk->prl,
@@ -1670,22 +1692,32 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset,
break;
} else {
/* overflow, mark as invalid */
xe_page_reclaim_list_invalidate(xe_walk->prl);
vm_dbg(&xe->drm,
"PRL invalidate: overflow while adding pte=%#llx",
pte);
xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl,
"overflow while adding pte=%#llx",
pte);
break;
}
}
}
/* If aborting page walk early, invalidate PRL since PTE may be dropped from this abort */
if (xe_pt_check_kill(addr, next, level - 1, xe_child, action, walk) &&
xe_walk->prl && level > 1 && xe_child->base.children && xe_child->num_live != 0) {
xe_page_reclaim_list_invalidate(xe_walk->prl);
vm_dbg(&xe->drm,
"PRL invalidate: kill at level=%u addr=%#llx next=%#llx num_live=%u\n",
level, addr, next, xe_child->num_live);
killed = xe_pt_check_kill(addr, next, level - 1, xe_child, action, walk);
/*
* Verify PRL is active and if entry is not a leaf pte (base.children conditions),
* there is a potential need to invalidate the PRL if any PTE (num_live) are dropped.
*/
if (xe_walk->prl && level > 1 && xe_child->num_live &&
xe_child->base.children && xe_child->base.children[first]) {
bool covered = xe_pt_covers(addr, next, xe_child->level, &xe_walk->base);
/*
* If aborting page walk early (kill) or page walk completes the full range
* we need to invalidate the PRL.
*/
if (killed || covered)
xe_page_reclaim_list_abort(xe_walk->tile->primary_gt, xe_walk->prl,
"kill at level=%u addr=%#llx next=%#llx num_live=%u",
level, addr, next, xe_child->num_live);
}
return 0;

View File

@@ -20,6 +20,7 @@ enum xe_cache_level {
XE_CACHE_WT,
XE_CACHE_WB,
XE_CACHE_NONE_COMPRESSION, /*UC + COH_NONE + COMPRESSION */
XE_CACHE_WB_COMPRESSION,
__XE_CACHE_LEVEL_COUNT,
};

View File

@@ -15,7 +15,6 @@
#include "xe_force_wake.h"
#include "xe_guc_submit.h"
#include "xe_gsc_proxy.h"
#include "xe_gt.h"
#include "xe_gt_types.h"
#include "xe_huc.h"
#include "xe_mmio.h"

View File

@@ -11,7 +11,7 @@
#include <drm/drm_managed.h>
#include <drm/drm_print.h>
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_pxp.h"
#include "xe_pxp_types.h"
#include "regs/xe_irq_regs.h"

Some files were not shown because too many files have changed in this diff Show More