mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-03-22 07:27:12 +08:00
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:
@@ -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
|
||||
|
||||
@@ -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 won’t 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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 = >->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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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_ */
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(>->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(>->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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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>";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 */
|
||||
|
||||
|
||||
@@ -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(>->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(>->reg_sr, gt);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"),
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
|
||||
/*
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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 *
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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, ®_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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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(>_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);
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
*/
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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"
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user