From 155c77f45f63dd58a37eeb0896b0b140ab785836 Mon Sep 17 00:00:00 2001 From: Maciej Patelczyk Date: Wed, 11 Dec 2024 12:17:26 +0100 Subject: [PATCH 001/130] drm/xe: introduce xe_gt_reset and xe_gt_wait_for_reset Add synchronous version gt reset as there are few places where it is expected. Also add a wait helper to wait until gt reset is done. Signed-off-by: Maciej Patelczyk Reviewed-by: Lucas De Marchi Fixes: f3bc5bb4d53d ("drm/xe: Allow userspace to configure CCS mode") Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20241211111727.1481476-2-maciej.patelczyk@intel.com Signed-off-by: Nirmoy Das --- drivers/gpu/drm/xe/tests/xe_bo.c | 7 +++---- drivers/gpu/drm/xe/tests/xe_mocs.c | 3 +-- drivers/gpu/drm/xe/xe_gt.h | 25 +++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_gt_debugfs.c | 4 +--- 4 files changed, 30 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/xe/tests/xe_bo.c b/drivers/gpu/drm/xe/tests/xe_bo.c index 405ff904153ef..6795d1d916e45 100644 --- a/drivers/gpu/drm/xe/tests/xe_bo.c +++ b/drivers/gpu/drm/xe/tests/xe_bo.c @@ -264,10 +264,9 @@ static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struc * however seems quite fragile not to also restart the GT. Try * to do that here by triggering a GT reset. */ - for_each_gt(__gt, xe, id) { - xe_gt_reset_async(__gt); - flush_work(&__gt->reset.worker); - } + for_each_gt(__gt, xe, id) + xe_gt_reset(__gt); + if (err) { KUNIT_FAIL(test, "restore kernel err=%pe\n", ERR_PTR(err)); diff --git a/drivers/gpu/drm/xe/tests/xe_mocs.c b/drivers/gpu/drm/xe/tests/xe_mocs.c index d3f71d13eb818..ef1e5256c56a8 100644 --- a/drivers/gpu/drm/xe/tests/xe_mocs.c +++ b/drivers/gpu/drm/xe/tests/xe_mocs.c @@ -162,8 +162,7 @@ static int mocs_reset_test_run_device(struct xe_device *xe) if (flags & HAS_LNCF_MOCS) read_l3cc_table(gt, &mocs.table); - xe_gt_reset_async(gt); - flush_work(>->reset.worker); + xe_gt_reset(gt); kunit_info(test, "mocs_reset_test after reset\n"); if (flags & HAS_GLOBAL_MOCS) diff --git a/drivers/gpu/drm/xe/xe_gt.h b/drivers/gpu/drm/xe/xe_gt.h index 4e4e8e103419a..e504cc33ade4f 100644 --- a/drivers/gpu/drm/xe/xe_gt.h +++ b/drivers/gpu/drm/xe/xe_gt.h @@ -56,6 +56,31 @@ void xe_gt_sanitize(struct xe_gt *gt); int xe_gt_sanitize_freq(struct xe_gt *gt); void xe_gt_remove(struct xe_gt *gt); +/** + * xe_gt_wait_for_reset - wait for gt's async reset to finalize. + * @gt: GT structure + * Return: + * %true if it waited for the work to finish execution, + * %false if there was no scheduled reset or it was done. + */ +static inline bool xe_gt_wait_for_reset(struct xe_gt *gt) +{ + return flush_work(>->reset.worker); +} + +/** + * xe_gt_reset - perform synchronous reset + * @gt: GT structure + * Return: + * %true if it waited for the reset to finish, + * %false if there was no scheduled reset. + */ +static inline bool xe_gt_reset(struct xe_gt *gt) +{ + xe_gt_reset_async(gt); + return xe_gt_wait_for_reset(gt); +} + /** * xe_gt_any_hw_engine_by_reset_domain - scan the list of engines and return the * first that matches the same reset domain as @class diff --git a/drivers/gpu/drm/xe/xe_gt_debugfs.c b/drivers/gpu/drm/xe/xe_gt_debugfs.c index 3e8c351a0eab0..e7792858b1e46 100644 --- a/drivers/gpu/drm/xe/xe_gt_debugfs.c +++ b/drivers/gpu/drm/xe/xe_gt_debugfs.c @@ -132,11 +132,9 @@ static int force_reset(struct xe_gt *gt, struct drm_printer *p) static int force_reset_sync(struct xe_gt *gt, struct drm_printer *p) { xe_pm_runtime_get(gt_to_xe(gt)); - xe_gt_reset_async(gt); + xe_gt_reset(gt); xe_pm_runtime_put(gt_to_xe(gt)); - flush_work(>->reset.worker); - return 0; } From 480fb9806e2e073532f7786166287114c696b340 Mon Sep 17 00:00:00 2001 From: Maciej Patelczyk Date: Wed, 11 Dec 2024 12:17:27 +0100 Subject: [PATCH 002/130] drm/xe: make change ccs_mode a synchronous action If ccs_mode is being modified via /sys/class/drm/cardX/device/tileY/gtY/ccs_mode the asynchronous reset is triggered and the write returns immediately. With that some test receive false information about number of CCS engines or even fail if they proceed without delay after changing the ccs_mode. Changing the ccs_mode change from async to sync to prevent failures in tests. Signed-off-by: Maciej Patelczyk Reviewed-by: Lucas De Marchi Fixes: f3bc5bb4d53d ("drm/xe: Allow userspace to configure CCS mode") Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20241211111727.1481476-3-maciej.patelczyk@intel.com Signed-off-by: Nirmoy Das --- drivers/gpu/drm/xe/xe_gt_ccs_mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_gt_ccs_mode.c b/drivers/gpu/drm/xe/xe_gt_ccs_mode.c index b6adfb9f20306..50fffc9ebf62a 100644 --- a/drivers/gpu/drm/xe/xe_gt_ccs_mode.c +++ b/drivers/gpu/drm/xe/xe_gt_ccs_mode.c @@ -150,7 +150,7 @@ ccs_mode_store(struct device *kdev, struct device_attribute *attr, xe_gt_info(gt, "Setting compute mode to %d\n", num_engines); gt->ccs_mode = num_engines; xe_gt_record_user_engines(gt); - xe_gt_reset_async(gt); + xe_gt_reset(gt); } mutex_unlock(&xe->drm.filelist_mutex); From 92029e0baa5313ba208103f90086f59070bbf93b Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Wed, 8 Jan 2025 15:13:23 +0100 Subject: [PATCH 003/130] drm/xe/ptl: Apply Wa_14023061436 Enable WMTP for the BTD kernel to address Wa14023061436 by setting the proper TDL Chicken Bit. v2: Apply it on engine_was[] as this register is not part of LRC(Matt) Apply it for first_render_or_compute in case this gets extended to compute only platforms(Matt). Cc: Gustavo Sousa Cc: Matt Roper Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20250108141323.311601-1-nirmoy.das@intel.com Signed-off-by: Nirmoy Das --- drivers/gpu/drm/xe/regs/xe_gt_regs.h | 3 +++ drivers/gpu/drm/xe/xe_wa.c | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index 162f18e975dae..b4283ac030f41 100644 --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h @@ -500,6 +500,9 @@ #define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11) #define DIS_ATOMIC_CHAINING_TYPED_WRITES REG_BIT(3) +#define TDL_CHICKEN XE_REG_MCR(0xe5f4, XE_REG_OPTION_MASKED) +#define QID_WAIT_FOR_THREAD_NOT_RUN_DISABLE REG_BIT(12) + #define LSC_CHICKEN_BIT_0 XE_REG_MCR(0xe7c8) #define DISABLE_D8_D16_COASLESCE REG_BIT(30) #define WR_REQ_CHAINING_DIS REG_BIT(26) diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 570fe03764025..744dba4fdb58b 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -613,6 +613,11 @@ static const struct xe_rtp_entry_sr engine_was[] = { XE_RTP_ACTIONS(FIELD_SET(SAMPLER_MODE, SMP_WAIT_FETCH_MERGING_COUNTER, SMP_FORCE_128B_OVERFETCH)) }, + { XE_RTP_NAME("14023061436"), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3001), + FUNC(xe_rtp_match_first_render_or_compute)), + XE_RTP_ACTIONS(SET(TDL_CHICKEN, QID_WAIT_FOR_THREAD_NOT_RUN_DISABLE)) + }, {} }; From c26f22dac3449d8a687237cdfc59a6445eb8f75a Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Fri, 10 Jan 2025 18:15:39 -0800 Subject: [PATCH 004/130] drm/xe/oa: Add missing VISACTL mux registers Add missing VISACTL mux registers required for some OA config's (e.g. RenderPipeCtrl). Fixes: cdf02fe1a94a ("drm/xe/oa/uapi: Add/remove OA config perf ops") Cc: stable@vger.kernel.org Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patchwork.freedesktop.org/patch/msgid/20250111021539.2920346-1-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_oa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 4e00a77289c50..eeb96b5f49e2a 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -2163,6 +2163,7 @@ static const struct xe_mmio_range xe2_oa_mux_regs[] = { { .start = 0x5194, .end = 0x5194 }, /* SYS_MEM_LAT_MEASURE_MERTF_GRP_3D */ { .start = 0x8704, .end = 0x8704 }, /* LMEM_LAT_MEASURE_MCFG_GRP */ { .start = 0xB1BC, .end = 0xB1BC }, /* L3_BANK_LAT_MEASURE_LBCF_GFX */ + { .start = 0xD0E0, .end = 0xD0F4 }, /* VISACTL */ { .start = 0xE18C, .end = 0xE18C }, /* SAMPLER_MODE */ { .start = 0xE590, .end = 0xE590 }, /* TDL_LSC_LAT_MEASURE_TDL_GFX */ { .start = 0x13000, .end = 0x137FC }, /* PES_0_PESL0 - PES_63_UPPER_PESL3 */ From d160dc6f53914d729be7fcb7afbd0e9e6a3725b2 Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Fri, 10 Jan 2025 09:33:09 -0800 Subject: [PATCH 005/130] drm/xe: Add locks in gtidle code The update of the residency values needs to be protected by a lock to avoid multiple entrypoints, for example when multiple userspace clients read the sysfs file. Other in-kernel clients are going to be added to sample these values, making the problem worse. Protect those updates with a raw_spinlock so it can be called by future integration with perf pmu. Suggested-by: Lucas De Marchi Cc: Rodrigo Vivi Cc: Lucas De Marchi Signed-off-by: Vinay Belgaumkar Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20250110173308.2412232-2-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_gt_idle.c | 23 ++++++++++++++++++++--- drivers/gpu/drm/xe/xe_gt_idle.h | 1 + drivers/gpu/drm/xe/xe_gt_idle_types.h | 3 +++ 3 files changed, 24 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_idle.c b/drivers/gpu/drm/xe/xe_gt_idle.c index ffd3ba7f66561..fbbace7b0b12a 100644 --- a/drivers/gpu/drm/xe/xe_gt_idle.c +++ b/drivers/gpu/drm/xe/xe_gt_idle.c @@ -69,6 +69,8 @@ static u64 get_residency_ms(struct xe_gt_idle *gtidle, u64 cur_residency) { u64 delta, overflow_residency, prev_residency; + lockdep_assert_held(>idle->lock); + overflow_residency = BIT_ULL(32); /* @@ -275,8 +277,21 @@ static ssize_t idle_status_show(struct device *dev, return sysfs_emit(buff, "%s\n", gt_idle_state_to_string(state)); } -static DEVICE_ATTR_RO(idle_status); +u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle) +{ + struct xe_guc_pc *pc = gtidle_to_pc(gtidle); + u64 residency; + unsigned long flags; + + raw_spin_lock_irqsave(>idle->lock, flags); + residency = get_residency_ms(gtidle, gtidle->idle_residency(pc)); + raw_spin_unlock_irqrestore(>idle->lock, flags); + + return residency; +} + +static DEVICE_ATTR_RO(idle_status); static ssize_t idle_residency_ms_show(struct device *dev, struct device_attribute *attr, char *buff) { @@ -285,10 +300,10 @@ static ssize_t idle_residency_ms_show(struct device *dev, u64 residency; xe_pm_runtime_get(pc_to_xe(pc)); - residency = gtidle->idle_residency(pc); + residency = xe_gt_idle_residency_msec(gtidle); xe_pm_runtime_put(pc_to_xe(pc)); - return sysfs_emit(buff, "%llu\n", get_residency_ms(gtidle, residency)); + return sysfs_emit(buff, "%llu\n", residency); } static DEVICE_ATTR_RO(idle_residency_ms); @@ -331,6 +346,8 @@ int xe_gt_idle_init(struct xe_gt_idle *gtidle) if (!kobj) return -ENOMEM; + raw_spin_lock_init(>idle->lock); + if (xe_gt_is_media_type(gt)) { snprintf(gtidle->name, sizeof(gtidle->name), "gt%d-mc", gt->info.id); gtidle->idle_residency = xe_guc_pc_mc6_residency; diff --git a/drivers/gpu/drm/xe/xe_gt_idle.h b/drivers/gpu/drm/xe/xe_gt_idle.h index 4455a6501cb07..591a01e181bcc 100644 --- a/drivers/gpu/drm/xe/xe_gt_idle.h +++ b/drivers/gpu/drm/xe/xe_gt_idle.h @@ -17,5 +17,6 @@ void xe_gt_idle_disable_c6(struct xe_gt *gt); void xe_gt_idle_enable_pg(struct xe_gt *gt); void xe_gt_idle_disable_pg(struct xe_gt *gt); int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p); +u64 xe_gt_idle_residency_msec(struct xe_gt_idle *gtidle); #endif /* _XE_GT_IDLE_H_ */ diff --git a/drivers/gpu/drm/xe/xe_gt_idle_types.h b/drivers/gpu/drm/xe/xe_gt_idle_types.h index b8b297a3f8848..a3667c567f8a7 100644 --- a/drivers/gpu/drm/xe/xe_gt_idle_types.h +++ b/drivers/gpu/drm/xe/xe_gt_idle_types.h @@ -6,6 +6,7 @@ #ifndef _XE_GT_IDLE_SYSFS_TYPES_H_ #define _XE_GT_IDLE_SYSFS_TYPES_H_ +#include #include struct xe_guc_pc; @@ -31,6 +32,8 @@ struct xe_gt_idle { u64 cur_residency; /** @prev_residency: previous residency counter */ u64 prev_residency; + /** @lock: Lock protecting idle residency counters */ + raw_spinlock_t lock; /** @idle_status: get the current idle state */ enum xe_gt_idle_state (*idle_status)(struct xe_guc_pc *pc); /** @idle_residency: get idle residency counter */ From 3318ef9888d5b4f5c5a9473180fd0b16e9ef266d Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Mon, 6 Jan 2025 15:43:13 -0800 Subject: [PATCH 006/130] drm/xe: Remove unused "mmio_ext" code The "mmio_ext" and 'REG_EXT" code is currently unused on any existing platform. Going forward, this also isn't the design we want to use for any future platforms/features either, so we should just go ahead and remove the dead code to avoid confusion. mmio_ext was originally added in an attempt to hack around the early (mis)design of the Xe driver, which used xe_gt as the target for all register MMIO access, even those completely unrelated to the GT subunit of the hardware. With the introduction of commit 34953ee349dd ("drm/xe: Create dedicated xe_mmio structure") and its follow-up patches, that misdesign has been corrected and access to register MMIO regions specific to hardware units is now done through xe_mmio structures which encapsulate an iomap, region size, and some other metadata. Although all of the registers used by the driver today happen to fall within one specific PCI BAR region, and thus re-use a single device-wide iomap, there's no requirement that this stay true for future platforms or features. I.e., if a future platform adds a new 'foo' hardware unit that exists at a different area in the BAR, or even in a completely different BAR, then that would be handled by doing a separate iomap of that unit's register region and wrapping it in its own 'struct xe_mmio foo_regs' structure. The pointer to the new 'foo_regs' could be placed within the xe_device, xe_tile, xe_gt, etc., according to where the new hardware unit falls within the current hardware hierarchy. This effectively reverts the following commits, although parts of these commits had already vanished or changed with the earlier xe_mmio refactor work: - commit 399a13323f0d ("drm/xe: add 28-bit address support in struct xe_reg") - commit fdef72e02e20 ("drm/xe: add a flag to bypass multi-tile config from MTCFG reg") - commit 866b2b176434 ("drm/xe: add MMIO extension support flags") - commit ef29b390c734 ("drm/xe: map MMIO BAR according to the num of tiles in device desc") - commit a4e2f3a299ea ("drm/xe: refactor xe_mmio_probe_tiles to support MMIO extension") Cc: Lucas De Marchi Cc: Rodrigo Vivi Cc: Koby Elbaz Acked-by: Maciej Patelczyk Reviewed-by: Reviewed-by: Lucas De Marchi Reviewed-by: Stuart Summers Link: https://patchwork.freedesktop.org/patch/msgid/20250106234312.2986065-2-matthew.d.roper@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/regs/xe_reg_defs.h | 16 +---------- drivers/gpu/drm/xe/xe_device_types.h | 11 -------- drivers/gpu/drm/xe/xe_mmio.c | 39 --------------------------- drivers/gpu/drm/xe/xe_pci.c | 3 --- drivers/gpu/drm/xe/xe_pci_types.h | 2 -- 5 files changed, 1 insertion(+), 70 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_reg_defs.h b/drivers/gpu/drm/xe/regs/xe_reg_defs.h index 0eedd6c26b1bf..89716172fbb85 100644 --- a/drivers/gpu/drm/xe/regs/xe_reg_defs.h +++ b/drivers/gpu/drm/xe/regs/xe_reg_defs.h @@ -21,7 +21,7 @@ struct xe_reg { union { struct { /** @addr: address */ - u32 addr:28; + u32 addr:22; /** * @masked: register is "masked", with upper 16bits used * to identify the bits that are updated on the lower @@ -41,10 +41,6 @@ struct xe_reg { * @vf: register is accessible from the Virtual Function. */ u32 vf:1; - /** - * @ext: access MMIO extension space for current register. - */ - u32 ext:1; }; /** @raw: Raw value with both address and options */ u32 raw; @@ -111,16 +107,6 @@ struct xe_reg_mcr { */ #define XE_REG(r_, ...) ((const struct xe_reg)XE_REG_INITIALIZER(r_, ##__VA_ARGS__)) -/** - * XE_REG_EXT - Create a struct xe_reg from extension offset and additional - * flags - * @r_: Register extension offset - * @...: Additional options like access mode. See struct xe_reg for available - * options. - */ -#define XE_REG_EXT(r_, ...) \ - ((const struct xe_reg)XE_REG_INITIALIZER(r_, ##__VA_ARGS__, .ext = 1)) - /** * XE_REG_MCR - Create a struct xe_reg_mcr from offset and additional flags * @r_: Register offset diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 8a7b159724135..16ebb2859877f 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -186,13 +186,6 @@ struct xe_tile { */ struct xe_mmio mmio; - /** - * @mmio_ext: MMIO-extension info for a tile. - * - * Each tile has its own additional 256MB (28-bit) MMIO-extension space. - */ - struct xe_mmio mmio_ext; - /** @mem: memory management info for tile */ struct { /** @@ -263,8 +256,6 @@ struct xe_device { const char *graphics_name; /** @info.media_name: media IP name */ const char *media_name; - /** @info.tile_mmio_ext_size: size of MMIO extension space, per-tile */ - u32 tile_mmio_ext_size; /** @info.graphics_verx100: graphics IP version */ u32 graphics_verx100; /** @info.media_verx100: media IP version */ @@ -314,8 +305,6 @@ struct xe_device { u8 has_heci_gscfi:1; /** @info.has_llc: Device has a shared CPU+GPU last level cache */ u8 has_llc:1; - /** @info.has_mmio_ext: Device has extra MMIO address range */ - u8 has_mmio_ext:1; /** @info.has_range_tlb_invalidation: Has range based TLB invalidations */ u8 has_range_tlb_invalidation:1; /** @info.has_sriov: Supports SR-IOV */ diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index a48f239cad1c5..d321a21aacf02 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -103,50 +103,11 @@ static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) } } -/* - * On top of all the multi-tile MMIO space there can be a platform-dependent - * extension for each tile, resulting in a layout like below: - * - * .----------------------. <- ext_base + tile_count * tile_mmio_ext_size - * | .... | - * |----------------------| <- ext_base + 2 * tile_mmio_ext_size - * | tile1->mmio_ext.regs | - * |----------------------| <- ext_base + 1 * tile_mmio_ext_size - * | tile0->mmio_ext.regs | - * |======================| <- ext_base = tile_count * tile_mmio_size - * | | - * | mmio.regs | - * | | - * '----------------------' <- 0MB - * - * Set up the tile[]->mmio_ext pointers/sizes. - */ -static void mmio_extension_setup(struct xe_device *xe, size_t tile_mmio_size, - size_t tile_mmio_ext_size) -{ - struct xe_tile *tile; - void __iomem *regs; - u8 id; - - if (!xe->info.has_mmio_ext) - return; - - regs = xe->mmio.regs + tile_mmio_size * xe->info.tile_count; - for_each_tile(tile, xe, id) { - tile->mmio_ext.regs_size = tile_mmio_ext_size; - tile->mmio_ext.regs = regs; - tile->mmio_ext.tile = tile; - regs += tile_mmio_ext_size; - } -} - int xe_mmio_probe_tiles(struct xe_device *xe) { size_t tile_mmio_size = SZ_16M; - size_t tile_mmio_ext_size = xe->info.tile_mmio_ext_size; mmio_multi_tile_setup(xe, tile_mmio_size); - mmio_extension_setup(xe, tile_mmio_size, tile_mmio_ext_size); return devm_add_action_or_reset(xe->drm.dev, tiles_fini, xe); } diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 39be74848e447..48d1c81d441e2 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -61,7 +61,6 @@ struct xe_device_desc { u8 has_heci_gscfi:1; u8 has_heci_cscfi:1; u8 has_llc:1; - u8 has_mmio_ext:1; u8 has_sriov:1; u8 skip_guc_pc:1; u8 skip_mtcfg:1; @@ -617,7 +616,6 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.has_heci_gscfi = desc->has_heci_gscfi; xe->info.has_heci_cscfi = desc->has_heci_cscfi; xe->info.has_llc = desc->has_llc; - xe->info.has_mmio_ext = desc->has_mmio_ext; xe->info.has_sriov = desc->has_sriov; xe->info.skip_guc_pc = desc->skip_guc_pc; xe->info.skip_mtcfg = desc->skip_mtcfg; @@ -677,7 +675,6 @@ static int xe_info_init(struct xe_device *xe, xe->info.graphics_name = graphics_desc->name; xe->info.media_name = media_desc ? media_desc->name : "none"; - xe->info.tile_mmio_ext_size = graphics_desc->tile_mmio_ext_size; xe->info.dma_mask_size = graphics_desc->dma_mask_size; xe->info.vram_flags = graphics_desc->vram_flags; diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h index 79b0f80376a4d..873efec5cdee8 100644 --- a/drivers/gpu/drm/xe/xe_pci_types.h +++ b/drivers/gpu/drm/xe/xe_pci_types.h @@ -20,8 +20,6 @@ struct xe_graphics_desc { u64 hw_engine_mask; /* hardware engines provided by graphics IP */ - u32 tile_mmio_ext_size; /* size of MMIO extension space, per-tile */ - u8 max_remote_tiles:2; u8 has_asid:1; From 0af944f0e3082ff517958b1cea76fb9b8cb379dd Mon Sep 17 00:00:00 2001 From: Oak Zeng Date: Fri, 10 Jan 2025 16:01:37 -0500 Subject: [PATCH 007/130] drm/xe: Reject BO eviction if BO is bound to current VM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is a follow up fix for https://patchwork.freedesktop.org/patch/msgid/20241203021929.1919730-1-oak.zeng@intel.com The overall goal is to fail vm_bind when there is memory pressure. See more details in the commit message of above patch. Abbove patch fixes the issue when user pass in a vm_id parameter during gem_create. If user doesn't pass in a vm_id during gem_create, above patch doesn't help. This patch further reject BO eviction (which could be triggered by bo validation) if BO is bound to the current VM. vm_bind could fail due to the eviction failure. The BO to VM reverse mapping structure is used to determine whether BO is bound to VM. v2: Move vm_bo definition from function scope to if(evict) clause (Thomas) Further constraint the condition by adding ctx->resv (Thomas) Add a short comment describe the change. Suggested-by: Thomas Hellström Signed-off-by: Oak Zeng Reviewed-by: Thomas Hellström Signed-off-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20250110210137.3181576-1-oak.zeng@intel.com --- drivers/gpu/drm/xe/xe_bo.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 3f5391d416d46..4f077c11e8e23 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -713,6 +713,21 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict, goto out; } + /* Reject BO eviction if BO is bound to current VM. */ + if (evict && ctx->resv) { + struct drm_gpuvm_bo *vm_bo; + + drm_gem_for_each_gpuvm_bo(vm_bo, &bo->ttm.base) { + struct xe_vm *vm = gpuvm_to_vm(vm_bo->vm); + + if (xe_vm_resv(vm) == ctx->resv && + xe_vm_in_preempt_fence_mode(vm)) { + ret = -EBUSY; + goto out; + } + } + } + /* * Failed multi-hop where the old_mem is still marked as * TTM_PL_FLAG_TEMPORARY, should just be a dummy move. From aaab5404b16f19b06c7d88787d7ba18d91eeb854 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 15 Jan 2025 09:50:52 -0500 Subject: [PATCH 008/130] drm/xe: Introduce GuC PC debugfs Allows the visualization of the current GuC power conservation status and policies. v2: Fix DCC msg (Vinay) v3: Simplify pc_get_state_string (Jonathan) Reviewed-by: Vinay Belgaumkar Reviewed-by: Jonathan Cavitt Link: https://patchwork.freedesktop.org/patch/msgid/20250115145053.1142023-1-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_guc_debugfs.c | 15 ++++++++ drivers/gpu/drm/xe/xe_guc_pc.c | 59 +++++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_guc_pc.h | 2 + 3 files changed, 76 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_guc_debugfs.c b/drivers/gpu/drm/xe/xe_guc_debugfs.c index 995b306aced77..0aff1d462bc01 100644 --- a/drivers/gpu/drm/xe/xe_guc_debugfs.c +++ b/drivers/gpu/drm/xe/xe_guc_debugfs.c @@ -13,6 +13,7 @@ #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" @@ -60,10 +61,24 @@ static int guc_ctb(struct seq_file *m, void *data) return 0; } +static int guc_pc(struct seq_file *m, void *data) +{ + struct xe_guc *guc = node_to_guc(m->private); + struct xe_device *xe = guc_to_xe(guc); + struct drm_printer p = drm_seq_file_printer(m); + + xe_pm_runtime_get(xe); + xe_guc_pc_print(&guc->pc, &p); + xe_pm_runtime_put(xe); + + return 0; +} + static const struct drm_info_list debugfs_list[] = { {"guc_info", guc_info, 0}, {"guc_log", guc_log, 0}, {"guc_ctb", guc_ctb, 0}, + {"guc_pc", guc_pc, 0}, }; void xe_guc_debugfs_register(struct xe_guc *guc, struct dentry *parent) diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c index df7f130fb663f..43f9617baba29 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.c +++ b/drivers/gpu/drm/xe/xe_guc_pc.c @@ -8,6 +8,7 @@ #include #include +#include #include #include "abi/guc_actions_slpc_abi.h" @@ -1131,3 +1132,61 @@ int xe_guc_pc_init(struct xe_guc_pc *pc) return devm_add_action_or_reset(xe->drm.dev, xe_guc_pc_fini_hw, pc); } + +static const char *pc_get_state_string(struct xe_guc_pc *pc) +{ + switch (slpc_shared_data_read(pc, header.global_state)) { + case SLPC_GLOBAL_STATE_NOT_RUNNING: + return "not running"; + case SLPC_GLOBAL_STATE_INITIALIZING: + return "initializing"; + case SLPC_GLOBAL_STATE_RESETTING: + return "resetting"; + case SLPC_GLOBAL_STATE_RUNNING: + return "running"; + case SLPC_GLOBAL_STATE_SHUTTING_DOWN: + return "shutting down"; + case SLPC_GLOBAL_STATE_ERROR: + return "error"; + default: + return "unknown"; + } +} + +/** + * xe_guc_pc_print - Print GuC's Power Conservation information for debug + * @pc: Xe_GuC_PC instance + * @p: drm_printer + */ +void xe_guc_pc_print(struct xe_guc_pc *pc, struct drm_printer *p) +{ + drm_printf(p, "SLPC Shared Data Header:\n"); + drm_printf(p, "\tSize: %x\n", slpc_shared_data_read(pc, header.size)); + drm_printf(p, "\tGlobal State: %s\n", pc_get_state_string(pc)); + + if (pc_action_query_task_state(pc)) + return; + + drm_printf(p, "\nSLPC Tasks Status:\n"); + drm_printf(p, "\tGTPERF enabled: %s\n", + str_yes_no(slpc_shared_data_read(pc, task_state_data.status) & + SLPC_GTPERF_TASK_ENABLED)); + drm_printf(p, "\tDCC enabled: %s\n", + str_yes_no(slpc_shared_data_read(pc, task_state_data.status) & + SLPC_DCC_TASK_ENABLED)); + drm_printf(p, "\tDCC in use: %s\n", + str_yes_no(slpc_shared_data_read(pc, task_state_data.status) & + SLPC_IN_DCC)); + drm_printf(p, "\tBalancer enabled: %s\n", + str_yes_no(slpc_shared_data_read(pc, task_state_data.status) & + SLPC_BALANCER_ENABLED)); + drm_printf(p, "\tIBC enabled: %s\n", + str_yes_no(slpc_shared_data_read(pc, task_state_data.status) & + SLPC_IBC_TASK_ENABLED)); + drm_printf(p, "\tBalancer IA LMT enabled: %s\n", + str_yes_no(slpc_shared_data_read(pc, task_state_data.status) & + SLPC_BALANCER_IA_LMT_ENABLED)); + drm_printf(p, "\tBalancer IA LMT active: %s\n", + str_yes_no(slpc_shared_data_read(pc, task_state_data.status) & + SLPC_BALANCER_IA_LMT_ACTIVE)); +} diff --git a/drivers/gpu/drm/xe/xe_guc_pc.h b/drivers/gpu/drm/xe/xe_guc_pc.h index 619f59cd633c5..39102b79602fd 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.h +++ b/drivers/gpu/drm/xe/xe_guc_pc.h @@ -10,6 +10,7 @@ struct xe_guc_pc; enum slpc_gucrc_mode; +struct drm_printer; int xe_guc_pc_init(struct xe_guc_pc *pc); int xe_guc_pc_start(struct xe_guc_pc *pc); @@ -17,6 +18,7 @@ int xe_guc_pc_stop(struct xe_guc_pc *pc); int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc); int xe_guc_pc_override_gucrc_mode(struct xe_guc_pc *pc, enum slpc_gucrc_mode mode); int xe_guc_pc_unset_gucrc_mode(struct xe_guc_pc *pc); +void xe_guc_pc_print(struct xe_guc_pc *pc, struct drm_printer *p); u32 xe_guc_pc_get_act_freq(struct xe_guc_pc *pc); int xe_guc_pc_get_cur_freq(struct xe_guc_pc *pc, u32 *freq); From 50554bf3e56dd0c78ef1eedb685d0ab36c9c9987 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 15 Jan 2025 09:50:53 -0500 Subject: [PATCH 009/130] drm/xe/lnl: Enable GuC SLPC DCC task Enable DCC (Duty Cycle Control) in Lunar Lake. DCC is the SLPC task that tries to keep the GT from operating inefficiently when thermally constrained. Although the recommendation is to enable it, LNL GuC is leaving it disabled by default on LNL. It would minimize the GT frequency oscillation on throttled scenarios, which could potentially reduce latencies. v2: Move set_policies call after wait for running state, so we ensure it is not overwritten. (Vinay) v3: Fix English in the commit message (Jonathan) v4: Also set disable to 0 so DCC can really get into effect. v5: Avoid lnl_ prefix (Vinay) v6: Finish renaming... Reviewed-by: Vinay Belgaumkar Reviewed-by: Jonathan Cavitt #v3 Link: https://patchwork.freedesktop.org/patch/msgid/20250115145053.1142023-2-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_guc_pc.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c index 43f9617baba29..44b5211066efa 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.c +++ b/drivers/gpu/drm/xe/xe_guc_pc.c @@ -993,6 +993,27 @@ static int pc_init_freqs(struct xe_guc_pc *pc) return ret; } +static int slpc_enable_dcc(struct xe_guc_pc *pc) +{ + int ret; + + ret = pc_action_set_param(pc, SLPC_PARAM_TASK_ENABLE_DCC, 1); + if (ret) + return ret; + + return pc_action_set_param(pc, SLPC_PARAM_TASK_DISABLE_DCC, 0); +} + +static int slpc_set_policies(struct xe_guc_pc *pc) +{ + struct xe_device *xe = pc_to_xe(pc); + + if (xe->info.platform == XE_LUNARLAKE) + return slpc_enable_dcc(pc); + + return 0; +} + /** * xe_guc_pc_start - Start GuC's Power Conservation component * @pc: Xe_GuC_PC instance @@ -1037,6 +1058,10 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) goto out; } + ret = slpc_set_policies(pc); + if (ret) + goto out; + ret = pc_init_freqs(pc); if (ret) goto out; From 11a64adcdbcc3028b96e440bc33fa76e2e825c10 Mon Sep 17 00:00:00 2001 From: Francois Dugast Date: Tue, 14 Jan 2025 12:38:53 -0800 Subject: [PATCH 010/130] drm/xe/xe3: Generate and store the L3 bank mask On Xe3, the register used to indicate which L3 banks are enabled on the system is a new one called MIRROR_L3BANK_ENABLE. Each bit represents one bank enabled in each node. Extend the existing topology code for Xe3 to read this register and generate the correct L3 bank mask, which can be read by user space throug the topology query. Bspec: 72573, 73439 Signed-off-by: Francois Dugast Signed-off-by: Matt Atwood Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20250114203853.35055-1-matthew.s.atwood@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/regs/xe_gt_regs.h | 3 +++ drivers/gpu/drm/xe/xe_gt_topology.c | 16 +++++++++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_gt_regs.h b/drivers/gpu/drm/xe/regs/xe_gt_regs.h index b4283ac030f41..096859072396d 100644 --- a/drivers/gpu/drm/xe/regs/xe_gt_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_gt_regs.h @@ -221,6 +221,9 @@ #define MIRROR_FUSE1 XE_REG(0x911c) +#define MIRROR_L3BANK_ENABLE XE_REG(0x9130) +#define XE3_L3BANK_ENABLE REG_GENMASK(31, 0) + #define XELP_EU_ENABLE XE_REG(0x9134) /* "_DISABLE" on Xe_LP */ #define XELP_EU_MASK REG_GENMASK(7, 0) #define XELP_GT_SLICE_ENABLE XE_REG(0x9138) diff --git a/drivers/gpu/drm/xe/xe_gt_topology.c b/drivers/gpu/drm/xe/xe_gt_topology.c index df2042db7ee68..516c81e3b8dd9 100644 --- a/drivers/gpu/drm/xe/xe_gt_topology.c +++ b/drivers/gpu/drm/xe/xe_gt_topology.c @@ -129,7 +129,8 @@ static void load_l3_bank_mask(struct xe_gt *gt, xe_l3_bank_mask_t l3_bank_mask) { struct xe_device *xe = gt_to_xe(gt); - u32 fuse3 = xe_mmio_read32(>->mmio, MIRROR_FUSE3); + struct xe_mmio *mmio = >->mmio; + u32 fuse3 = xe_mmio_read32(mmio, MIRROR_FUSE3); /* * PTL platforms with media version 30.00 do not provide proper values @@ -143,7 +144,16 @@ load_l3_bank_mask(struct xe_gt *gt, xe_l3_bank_mask_t l3_bank_mask) if (XE_WA(gt, no_media_l3)) return; - if (GRAPHICS_VER(xe) >= 20) { + if (GRAPHICS_VER(xe) >= 30) { + xe_l3_bank_mask_t per_node = {}; + u32 meml3_en = REG_FIELD_GET(XE2_NODE_ENABLE_MASK, fuse3); + u32 mirror_l3bank_enable = xe_mmio_read32(mmio, MIRROR_L3BANK_ENABLE); + u32 bank_val = REG_FIELD_GET(XE3_L3BANK_ENABLE, mirror_l3bank_enable); + + bitmap_from_arr32(per_node, &bank_val, 32); + gen_l3_mask_from_pattern(xe, l3_bank_mask, per_node, 32, + meml3_en); + } else if (GRAPHICS_VER(xe) >= 20) { xe_l3_bank_mask_t per_node = {}; u32 meml3_en = REG_FIELD_GET(XE2_NODE_ENABLE_MASK, fuse3); u32 bank_val = REG_FIELD_GET(XE2_GT_L3_MODE_MASK, fuse3); @@ -155,7 +165,7 @@ load_l3_bank_mask(struct xe_gt *gt, xe_l3_bank_mask_t l3_bank_mask) xe_l3_bank_mask_t per_node = {}; xe_l3_bank_mask_t per_mask_bit = {}; u32 meml3_en = REG_FIELD_GET(MEML3_EN_MASK, fuse3); - u32 fuse4 = xe_mmio_read32(>->mmio, XEHP_FUSE4); + u32 fuse4 = xe_mmio_read32(mmio, XEHP_FUSE4); u32 bank_val = REG_FIELD_GET(GT_L3_EXC_MASK, fuse4); bitmap_set_value8(per_mask_bit, 0x3, 0); From 174e9ce0daf6af791386e96e76e743eb59e8a401 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Mon, 13 Jan 2025 11:44:04 -0800 Subject: [PATCH 011/130] drm/xe/guc: Drop error messages about missing GuC logs The GuC log snapshot code would complain loudly if there was no GuC log to take a snapshot of or if the snapshot alloc failed. Originally, this code was only called on demand when a user (or developer) explicitly requested a dump of the log. Hence an error message was useful. However, it is now part of the general devcoredump file and is called for any GPU hang. Most people don't care about GuC logs and GPU hangs do not generally mean a kernel/GuC bug. More importantly, there are valid situations where there is no GuC log, e.g. SRIOV VFs. So drop the error message. Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/3958 Signed-off-by: John Harrison Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250113194405.2033085-1-John.C.Harrison@Intel.com --- drivers/gpu/drm/xe/xe_guc_log.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_log.c b/drivers/gpu/drm/xe/xe_guc_log.c index df4cfb698cdbc..80151ff6a71f8 100644 --- a/drivers/gpu/drm/xe/xe_guc_log.c +++ b/drivers/gpu/drm/xe/xe_guc_log.c @@ -149,16 +149,12 @@ struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log, size_t remain; int i; - if (!log->bo) { - xe_gt_err(gt, "GuC log buffer not allocated\n"); + if (!log->bo) return NULL; - } snapshot = xe_guc_log_snapshot_alloc(log, atomic); - if (!snapshot) { - xe_gt_err(gt, "GuC log snapshot not allocated\n"); + if (!snapshot) return NULL; - } remain = snapshot->size; for (i = 0; i < snapshot->num_chunks; i++) { From 75d37750a753e7ae079e470ea9699caeae756e3d Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Mon, 13 Jan 2025 17:12:01 +0530 Subject: [PATCH 012/130] drm/xe/mmap: Add mmap support for PCI memory barrier In order to avoid having userspace to use MI_MEM_FENCE, we are adding a mechanism for userspace to generate a PCI memory barrier with low overhead (avoiding IOCTL call as well as writing to VRAM will adds some overhead). This is implemented by memory-mapping a page as uncached that is backed by MMIO on the dGPU and thus allowing userspace to do memory write to the page without invoking an IOCTL. We are selecting the MMIO so that it is not accessible from the PCI bus so that the MMIO writes themselves are ignored, but the PCI memory barrier will still take action as the MMIO filtering will happen after the memory barrier effect. When we detect special defined offset in mmap(), We are mapping 4K page which contains the last of page of doorbell MMIO range to userspace for same purpose. For user to query special offset we are adding special flag in mmap_offset ioctl which needs to be passed as follows, struct drm_xe_gem_mmap_offset mmo = { .handle = 0, /* this must be 0 */ .flags = DRM_XE_MMAP_OFFSET_FLAG_PCI_BARRIER, }; igt_ioctl(fd, DRM_IOCTL_XE_GEM_MMAP_OFFSET, &mmo); map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, mmo); IGT : https://gitlab.freedesktop.org/drm/igt-gpu-tools/-/commit/b2dbc6f22815128c0dd5c737504f42e1f1a6ad62 UMD : https://github.com/intel/compute-runtime/pull/772 V7: - Dgpu filter added V6(MAuld) - Move physical mmap to fault handler - Modify kernel-doc and attach UMD PR when ready V5(MAuld) - Return invalid early in case of non 4K PAGE_SIZE - Format kernel-doc and add note for 4K PAGE_SIZE HW limit V4(MAuld) - Add kernel-doc for uapi change - Restrict page size to 4K V3(MAuld) - Remove offset defination from UAPI to be able to change later - Edit commit message for special flag addition V2(MAuld) - Add fault handler with dummy page to handle unplug device - Add Build check for special offset to be below normal start page - Test d3hot, mapping seems to be valid in d3hot as well - Add more info to commit message Cc: Matthew Auld Acked-by: Michal Mrozek Reviewed-by: Matthew Auld Signed-off-by: Tejas Upadhyay Signed-off-by: Matthew Auld Link: https://patchwork.freedesktop.org/patch/msgid/20250113114201.3178806-1-tejas.upadhyay@intel.com --- drivers/gpu/drm/xe/xe_bo.c | 19 +++++- drivers/gpu/drm/xe/xe_bo.h | 2 + drivers/gpu/drm/xe/xe_device.c | 107 ++++++++++++++++++++++++++++++++- include/uapi/drm/xe_drm.h | 29 ++++++++- 4 files changed, 154 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 4f077c11e8e23..78d19fd4670aa 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -2278,9 +2278,26 @@ int xe_gem_mmap_offset_ioctl(struct drm_device *dev, void *data, XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1])) return -EINVAL; - if (XE_IOCTL_DBG(xe, args->flags)) + if (XE_IOCTL_DBG(xe, args->flags & + ~DRM_XE_MMAP_OFFSET_FLAG_PCI_BARRIER)) return -EINVAL; + if (args->flags & DRM_XE_MMAP_OFFSET_FLAG_PCI_BARRIER) { + if (XE_IOCTL_DBG(xe, !IS_DGFX(xe))) + return -EINVAL; + + if (XE_IOCTL_DBG(xe, args->handle)) + return -EINVAL; + + if (XE_IOCTL_DBG(xe, PAGE_SIZE > SZ_4K)) + return -EINVAL; + + BUILD_BUG_ON(((XE_PCI_BARRIER_MMAP_OFFSET >> XE_PTE_SHIFT) + + SZ_4K) >= DRM_FILE_PAGE_OFFSET_START); + args->offset = XE_PCI_BARRIER_MMAP_OFFSET; + return 0; + } + gem_obj = drm_gem_object_lookup(file, args->handle); if (XE_IOCTL_DBG(xe, !gem_obj)) return -ENOENT; diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h index d9386ab031404..04995c5ced320 100644 --- a/drivers/gpu/drm/xe/xe_bo.h +++ b/drivers/gpu/drm/xe/xe_bo.h @@ -75,6 +75,8 @@ #define XE_BO_PROPS_INVALID (-1) +#define XE_PCI_BARRIER_MMAP_OFFSET (0x50 << XE_PTE_SHIFT) + struct sg_table; struct xe_bo *xe_bo_alloc(void); diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 5cbc96b214feb..6ecbf7dd396cb 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -232,12 +232,117 @@ static long xe_drm_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo #define xe_drm_compat_ioctl NULL #endif +static void barrier_open(struct vm_area_struct *vma) +{ + drm_dev_get(vma->vm_private_data); +} + +static void barrier_close(struct vm_area_struct *vma) +{ + drm_dev_put(vma->vm_private_data); +} + +static void barrier_release_dummy_page(struct drm_device *dev, void *res) +{ + struct page *dummy_page = (struct page *)res; + + __free_page(dummy_page); +} + +static vm_fault_t barrier_fault(struct vm_fault *vmf) +{ + struct drm_device *dev = vmf->vma->vm_private_data; + struct vm_area_struct *vma = vmf->vma; + vm_fault_t ret = VM_FAULT_NOPAGE; + pgprot_t prot; + int idx; + + prot = vm_get_page_prot(vma->vm_flags); + + if (drm_dev_enter(dev, &idx)) { + unsigned long pfn; + +#define LAST_DB_PAGE_OFFSET 0x7ff001 + pfn = PHYS_PFN(pci_resource_start(to_pci_dev(dev->dev), 0) + + LAST_DB_PAGE_OFFSET); + ret = vmf_insert_pfn_prot(vma, vma->vm_start, pfn, + pgprot_noncached(prot)); + drm_dev_exit(idx); + } else { + struct page *page; + + /* Allocate new dummy page to map all the VA range in this VMA to it*/ + page = alloc_page(GFP_KERNEL | __GFP_ZERO); + if (!page) + return VM_FAULT_OOM; + + /* Set the page to be freed using drmm release action */ + if (drmm_add_action_or_reset(dev, barrier_release_dummy_page, page)) + return VM_FAULT_OOM; + + ret = vmf_insert_pfn_prot(vma, vma->vm_start, page_to_pfn(page), + prot); + } + + return ret; +} + +static const struct vm_operations_struct vm_ops_barrier = { + .open = barrier_open, + .close = barrier_close, + .fault = barrier_fault, +}; + +static int xe_pci_barrier_mmap(struct file *filp, + struct vm_area_struct *vma) +{ + struct drm_file *priv = filp->private_data; + struct drm_device *dev = priv->minor->dev; + struct xe_device *xe = to_xe_device(dev); + + if (!IS_DGFX(xe)) + return -EINVAL; + + if (vma->vm_end - vma->vm_start > SZ_4K) + return -EINVAL; + + if (is_cow_mapping(vma->vm_flags)) + return -EINVAL; + + if (vma->vm_flags & (VM_READ | VM_EXEC)) + return -EINVAL; + + vm_flags_clear(vma, VM_MAYREAD | VM_MAYEXEC); + vm_flags_set(vma, VM_PFNMAP | VM_DONTEXPAND | VM_DONTDUMP | VM_IO); + vma->vm_ops = &vm_ops_barrier; + vma->vm_private_data = dev; + drm_dev_get(vma->vm_private_data); + + return 0; +} + +static int xe_mmap(struct file *filp, struct vm_area_struct *vma) +{ + struct drm_file *priv = filp->private_data; + struct drm_device *dev = priv->minor->dev; + + if (drm_dev_is_unplugged(dev)) + return -ENODEV; + + switch (vma->vm_pgoff) { + case XE_PCI_BARRIER_MMAP_OFFSET >> XE_PTE_SHIFT: + return xe_pci_barrier_mmap(filp, vma); + } + + return drm_gem_mmap(filp, vma); +} + static const struct file_operations xe_driver_fops = { .owner = THIS_MODULE, .open = drm_open, .release = drm_release_noglobal, .unlocked_ioctl = xe_drm_ioctl, - .mmap = drm_gem_mmap, + .mmap = xe_mmap, .poll = drm_poll, .read = drm_read, .compat_ioctl = xe_drm_compat_ioctl, diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index f62689ca861a4..cac607a30f6d3 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -811,6 +811,32 @@ struct drm_xe_gem_create { /** * struct drm_xe_gem_mmap_offset - Input of &DRM_IOCTL_XE_GEM_MMAP_OFFSET + * + * The @flags can be: + * - %DRM_XE_MMAP_OFFSET_FLAG_PCI_BARRIER - For user to query special offset + * for use in mmap ioctl. Writing to the returned mmap address will generate a + * PCI memory barrier with low overhead (avoiding IOCTL call as well as writing + * to VRAM which would also add overhead), acting like an MI_MEM_FENCE + * instruction. + * + * Note: The mmap size can be at most 4K, due to HW limitations. As a result + * this interface is only supported on CPU architectures that support 4K page + * size. The mmap_offset ioctl will detect this and gracefully return an + * error, where userspace is expected to have a different fallback method for + * triggering a barrier. + * + * Roughly the usage would be as follows: + * + * .. code-block:: C + * + * struct drm_xe_gem_mmap_offset mmo = { + * .handle = 0, // must be set to 0 + * .flags = DRM_XE_MMAP_OFFSET_FLAG_PCI_BARRIER, + * }; + * + * err = ioctl(fd, DRM_IOCTL_XE_GEM_MMAP_OFFSET, &mmo); + * map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, mmo.offset); + * map[i] = 0xdeadbeaf; // issue barrier */ struct drm_xe_gem_mmap_offset { /** @extensions: Pointer to the first extension struct, if any */ @@ -819,7 +845,8 @@ struct drm_xe_gem_mmap_offset { /** @handle: Handle for the object being mapped. */ __u32 handle; - /** @flags: Must be zero */ +#define DRM_XE_MMAP_OFFSET_FLAG_PCI_BARRIER (1 << 0) + /** @flags: Flags */ __u32 flags; /** @offset: The fake offset to use for subsequent mmap call */ From 758debf35b9cda5450e40996991a6e4b222899bd Mon Sep 17 00:00:00 2001 From: Matthew Brost Date: Mon, 13 Jan 2025 16:25:07 -0800 Subject: [PATCH 013/130] drm/xe: Mark ComputeCS read mode as UC on iGPU MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RING_CMD_CCTL read index should be UC on iGPU parts due to L3 caching structure. Having this as WB blocks ULLS from being enabled. Change to UC to unblock ULLS on iGPU. v2: - Drop internal communications commnet, bspec is updated Cc: Balasubramani Vivekanandan Cc: Michal Mrozek Cc: Paulo Zanoni Cc: José Roberto de Souza Cc: stable@vger.kernel.org Fixes: 328e089bfb37 ("drm/xe: Leverage ComputeCS read L3 caching") Signed-off-by: Matthew Brost Acked-by: Michal Mrozek Reviewed-by: Stuart Summers Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20250114002507.114087-1-matthew.brost@intel.com --- drivers/gpu/drm/xe/xe_hw_engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_hw_engine.c b/drivers/gpu/drm/xe/xe_hw_engine.c index ac9c666a9652a..fc447751fe786 100644 --- a/drivers/gpu/drm/xe/xe_hw_engine.c +++ b/drivers/gpu/drm/xe/xe_hw_engine.c @@ -422,7 +422,7 @@ hw_engine_setup_default_state(struct xe_hw_engine *hwe) * Bspec: 72161 */ const u8 mocs_write_idx = gt->mocs.uc_index; - const u8 mocs_read_idx = hwe->class == XE_ENGINE_CLASS_COMPUTE && + const u8 mocs_read_idx = hwe->class == XE_ENGINE_CLASS_COMPUTE && IS_DGFX(xe) && (GRAPHICS_VER(xe) >= 20 || xe->info.platform == XE_PVC) ? gt->mocs.wb_index : gt->mocs.uc_index; u32 ring_cmd_cctl_val = REG_FIELD_PREP(CMD_CCTL_WRITE_OVERRIDE_MASK, mocs_write_idx) | From 63060df6f709cbe494f0cfcaa613655862ba479a Mon Sep 17 00:00:00 2001 From: Oak Zeng Date: Wed, 18 Dec 2024 11:48:31 -0500 Subject: [PATCH 014/130] drm/xe: trace bo create Add a tracepoint to trace bo create. Signed-off-by: Oak Zeng Reviewed-by: Matthew Brost Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20241218164833.2364049-2-oak.zeng@intel.com Signed-off-by: Himal Prasad Ghimiray --- drivers/gpu/drm/xe/xe_bo.c | 1 + drivers/gpu/drm/xe/xe_trace_bo.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 78d19fd4670aa..cf0dc9e9c53eb 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -1659,6 +1659,7 @@ __xe_bo_create_locked(struct xe_device *xe, } } + trace_xe_bo_create(bo); return bo; err_unlock_put_bo: diff --git a/drivers/gpu/drm/xe/xe_trace_bo.h b/drivers/gpu/drm/xe/xe_trace_bo.h index ea50fee50c7de..3d7e6c80b0aa8 100644 --- a/drivers/gpu/drm/xe/xe_trace_bo.h +++ b/drivers/gpu/drm/xe/xe_trace_bo.h @@ -53,6 +53,11 @@ DEFINE_EVENT(xe_bo, xe_bo_validate, TP_ARGS(bo) ); +DEFINE_EVENT(xe_bo, xe_bo_create, + TP_PROTO(struct xe_bo *bo), + TP_ARGS(bo) +); + TRACE_EVENT(xe_bo_move, TP_PROTO(struct xe_bo *bo, uint32_t new_placement, uint32_t old_placement, bool move_lacks_source), From 861b27584d9055e4e1763341474ce8ce9dc6a55d Mon Sep 17 00:00:00 2001 From: Oak Zeng Date: Wed, 18 Dec 2024 11:48:32 -0500 Subject: [PATCH 015/130] drm/xe: Print vm flags in xe_vm trace print Print vm flags in xe_vm trace print. This is helpful to diagnosis the VM mode of operation. Signed-off-by: Oak Zeng Reviewed-by: Matthew Brost Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20241218164833.2364049-3-oak.zeng@intel.com Signed-off-by: Himal Prasad Ghimiray --- drivers/gpu/drm/xe/xe_trace_bo.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_trace_bo.h b/drivers/gpu/drm/xe/xe_trace_bo.h index 3d7e6c80b0aa8..082fadb5f99b6 100644 --- a/drivers/gpu/drm/xe/xe_trace_bo.h +++ b/drivers/gpu/drm/xe/xe_trace_bo.h @@ -190,16 +190,19 @@ DECLARE_EVENT_CLASS(xe_vm, __string(dev, __dev_name_vm(vm)) __field(struct xe_vm *, vm) __field(u32, asid) + __field(u32, flags) ), TP_fast_assign( __assign_str(dev); __entry->vm = vm; __entry->asid = vm->usm.asid; + __entry->flags = vm->flags; ), - TP_printk("dev=%s, vm=%p, asid=0x%05x", __get_str(dev), - __entry->vm, __entry->asid) + TP_printk("dev=%s, vm=%p, asid=0x%05x, vm flags=0x%05x", + __get_str(dev), __entry->vm, __entry->asid, + __entry->flags) ); DEFINE_EVENT(xe_vm, xe_vm_kill, From 22b1a53f282b1ad6692c6238a7446275854f0afb Mon Sep 17 00:00:00 2001 From: Oak Zeng Date: Wed, 18 Dec 2024 11:48:33 -0500 Subject: [PATCH 016/130] drm/xe: Print vm parameter in xe_vma trace Print the vm that the vma belongs to in the vma trace. This is useful to correlate VMA operations to the VM. Signed-off-by: Oak Zeng Reviewed-by: Matthew Brost Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20241218164833.2364049-4-oak.zeng@intel.com Signed-off-by: Himal Prasad Ghimiray --- drivers/gpu/drm/xe/xe_trace_bo.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_trace_bo.h b/drivers/gpu/drm/xe/xe_trace_bo.h index 082fadb5f99b6..ccebd5f0878e5 100644 --- a/drivers/gpu/drm/xe/xe_trace_bo.h +++ b/drivers/gpu/drm/xe/xe_trace_bo.h @@ -92,6 +92,7 @@ DECLARE_EVENT_CLASS(xe_vma, TP_STRUCT__entry( __string(dev, __dev_name_vma(vma)) __field(struct xe_vma *, vma) + __field(struct xe_vm *, vm) __field(u32, asid) __field(u64, start) __field(u64, end) @@ -101,14 +102,16 @@ DECLARE_EVENT_CLASS(xe_vma, TP_fast_assign( __assign_str(dev); __entry->vma = vma; + __entry->vm = xe_vma_vm(vma); __entry->asid = xe_vma_vm(vma)->usm.asid; __entry->start = xe_vma_start(vma); __entry->end = xe_vma_end(vma) - 1; __entry->ptr = xe_vma_userptr(vma); ), - TP_printk("dev=%s, vma=%p, asid=0x%05x, start=0x%012llx, end=0x%012llx, userptr=0x%012llx,", - __get_str(dev), __entry->vma, __entry->asid, __entry->start, + TP_printk("dev=%s, vma=%p, vm=%p, asid=0x%05x, start=0x%012llx, end=0x%012llx, userptr=0x%012llx", + __get_str(dev), __entry->vma, __entry->vm, + __entry->asid, __entry->start, __entry->end, __entry->ptr) ) From b824709ee1d0dbfed4b1757279c97fc0edad1e1a Mon Sep 17 00:00:00 2001 From: Oak Zeng Date: Mon, 13 Jan 2025 16:23:24 -0500 Subject: [PATCH 017/130] drm/xe: Fix a typo in xe_vm_doc.h s/vm->ttm.base.resv->lock/vm->gpuvm.r_obj->resv->lock Signed-off-by: Oak Zeng Reviewed-by: Maciej Patelczyk Link: https://patchwork.freedesktop.org/patch/msgid/20250113212324.3264218-1-oak.zeng@intel.com Signed-off-by: Himal Prasad Ghimiray --- drivers/gpu/drm/xe/xe_vm_doc.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_vm_doc.h b/drivers/gpu/drm/xe/xe_vm_doc.h index 0787869584036..1030ce214032c 100644 --- a/drivers/gpu/drm/xe/xe_vm_doc.h +++ b/drivers/gpu/drm/xe/xe_vm_doc.h @@ -431,7 +431,7 @@ * bind path also acquires this lock in write while the exec / compute mode * rebind worker acquires this lock in read mode. * - * VM dma-resv lock (vm->ttm.base.resv->lock) - WW lock. Protects VM dma-resv + * VM dma-resv lock (vm->gpuvm.r_obj->resv->lock) - WW lock. Protects VM dma-resv * slots which is shared with any private BO in the VM. Expected to be acquired * during VM binds, execs, and compute mode rebind worker. This lock is also * held when private BOs are being evicted. From 474c4dd29f666145dee7b5dce56d024a26e9550c Mon Sep 17 00:00:00 2001 From: Francois Dugast Date: Thu, 16 Jan 2025 13:45:32 +0100 Subject: [PATCH 018/130] drm/xe: Add missing SPDX license identifiers Ensure all Xe driver files have a proper SPDX license identifier, add it in files where it was missing. Link: https://patchwork.freedesktop.org/patch/msgid/20250116124532.1480351-1-francois.dugast@intel.com Signed-off-by: Francois Dugast Reviewed-by: Lucas De Marchi --- drivers/gpu/drm/xe/Kconfig.profile | 1 + drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/drivers/gpu/drm/xe/Kconfig.profile b/drivers/gpu/drm/xe/Kconfig.profile index ba17a25e8db3b..7530df998148f 100644 --- a/drivers/gpu/drm/xe/Kconfig.profile +++ b/drivers/gpu/drm/xe/Kconfig.profile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only config DRM_XE_JOB_TIMEOUT_MAX int "Default max job timeout (ms)" default 10000 # milliseconds diff --git a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h index 9c4cf050059ac..41d39d67817a1 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/gem/i915_gem_stolen.h @@ -1,3 +1,8 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2024 Intel Corporation + */ + #ifndef _I915_GEM_STOLEN_H_ #define _I915_GEM_STOLEN_H_ From bbd8429264baf8bc3c40cefda048560ae0eb7890 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 14 Nov 2024 18:59:54 +0100 Subject: [PATCH 019/130] drm/xe: Always setup GT MMIO adjustment data While we believed that xe_gt_mmio_init() will be called just once per GT, this might not be a case due to some tweaks that need to performed by the VF driver during early probe. To avoid leaving any stale data in case of the re-run, reset the GT MMIO adjustment data for the non-media GT case. Signed-off-by: Michal Wajdeczko Cc: Matt Roper Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20241114175955.2299-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 26e64530ada27..b5c313a3e9460 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -643,6 +643,9 @@ void xe_gt_mmio_init(struct xe_gt *gt) if (gt->info.type == XE_GT_TYPE_MEDIA) { gt->mmio.adj_offset = MEDIA_GT_GSI_OFFSET; gt->mmio.adj_limit = MEDIA_GT_GSI_LENGTH; + } else { + gt->mmio.adj_offset = 0; + gt->mmio.adj_limit = 0; } if (IS_SRIOV_VF(gt_to_xe(gt))) From 13265fe7426ec9ba5aa86baab913417ca361e8a4 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 14 Jan 2025 22:13:47 +0100 Subject: [PATCH 020/130] drm/xe/vf: Perform early GT MMIO initialization to read GMDID MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VFs need to communicate with the GuC to obtain the GMDID value and existing GuC functions used for that assume that the GT has it's MMIO members already setup. However, due to recent refactoring the gt->mmio is initialized later, and any attempt by the VF to use xe_mmio_read|write() from GuC functions will lead to NPD crash due to unset MMIO register address: [] xe 0000:00:02.1: [drm] Running in SR-IOV VF mode [] xe 0000:00:02.1: [drm] GT0: sending H2G MMIO 0x5507 [] BUG: unable to handle page fault for address: 0000000000190240 Since we are already tweaking the id and type of the primary GT to mimic it's a Media GT before initializing the GuC communication, we can also call xe_gt_mmio_init() to perform early setup of the gt->mmio which will make those GuC functions work again. Signed-off-by: Michal Wajdeczko Cc: Matt Roper Cc: Piotr Piórkowski Reviewed-by: Piotr Piórkowski Link: https://patchwork.freedesktop.org/patch/msgid/20250114211347.1083-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 48d1c81d441e2..bf35a18bf5e7e 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -501,6 +501,7 @@ static void read_gmdid(struct xe_device *xe, enum xe_gmdid_type type, u32 *ver, gt->info.type = XE_GT_TYPE_MAIN; } + xe_gt_mmio_init(gt); xe_guc_comm_init_early(>->uc.guc); /* Don't bother with GMDID if failed to negotiate the GuC ABI */ From 9cd3f4efc870463f17f6c29114c61fb6bfcaa291 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:41:54 +0100 Subject: [PATCH 021/130] drm/xe/sa: Always call drm_suballoc_manager_fini() After successful call to drm_suballoc_manager_init() we should make sure to call drm_suballoc_manager_fini() as it may include some cleanup code even if we didn't start using it for real. As we can abort init() early due to kvzalloc() failure, we should either explicitly call drm_suballoc_manager_fini() or, even better, postpone drm_suballoc_manager_init() once we finish all other preparation steps, so we can rely on fini() that will do cleanup. Signed-off-by: Michal Wajdeczko Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_sa.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c index e055bed7ae555..4e7aba445ebc8 100644 --- a/drivers/gpu/drm/xe/xe_sa.c +++ b/drivers/gpu/drm/xe/xe_sa.c @@ -57,8 +57,6 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 } sa_manager->bo = bo; sa_manager->is_iomem = bo->vmap.is_iomem; - - drm_suballoc_manager_init(&sa_manager->base, managed_size, align); sa_manager->gpu_addr = xe_bo_ggtt_addr(bo); if (bo->vmap.is_iomem) { @@ -72,6 +70,7 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 memset(sa_manager->cpu_ptr, 0, bo->ttm.base.size); } + drm_suballoc_manager_init(&sa_manager->base, managed_size, align); ret = drmm_add_action_or_reset(&xe->drm, xe_sa_bo_manager_fini, sa_manager); if (ret) From d29cddd49bed2c880e7c17724bcf3604e865c23a Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:41:55 +0100 Subject: [PATCH 022/130] drm/xe/sa: Drop redundant NULL assignments The sa_manager is drmm_kzalloc'ed so all members are already zero. And in case of kvzalloc() failure we are not returning pointer to the sa_manager at all, so no point in resetting .bo member. Signed-off-by: Michal Wajdeczko Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-3-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_sa.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c index 4e7aba445ebc8..eb314ca753559 100644 --- a/drivers/gpu/drm/xe/xe_sa.c +++ b/drivers/gpu/drm/xe/xe_sa.c @@ -44,8 +44,6 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 if (!sa_manager) return ERR_PTR(-ENOMEM); - sa_manager->bo = NULL; - bo = xe_managed_bo_create_pin_map(xe, tile, size, XE_BO_FLAG_VRAM_IF_DGFX(tile) | XE_BO_FLAG_GGTT | @@ -61,10 +59,8 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 if (bo->vmap.is_iomem) { sa_manager->cpu_ptr = kvzalloc(managed_size, GFP_KERNEL); - if (!sa_manager->cpu_ptr) { - sa_manager->bo = NULL; + if (!sa_manager->cpu_ptr) return ERR_PTR(-ENOMEM); - } } else { sa_manager->cpu_ptr = bo->vmap.vaddr; memset(sa_manager->cpu_ptr, 0, bo->ttm.base.size); From 97ee0e351f6ebbcb2a2dccdff726f75f728fede8 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:41:56 +0100 Subject: [PATCH 023/130] drm/xe/sa: Improve error message on init failure Instead of raw errno value we can print friendly error code and also print size of the buffer object that we fail to prepare. Signed-off-by: Michal Wajdeczko Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-4-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_sa.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c index eb314ca753559..0b87599759d7e 100644 --- a/drivers/gpu/drm/xe/xe_sa.c +++ b/drivers/gpu/drm/xe/xe_sa.c @@ -49,8 +49,8 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 XE_BO_FLAG_GGTT | XE_BO_FLAG_GGTT_INVALIDATE); if (IS_ERR(bo)) { - drm_err(&xe->drm, "failed to allocate bo for sa manager: %ld\n", - PTR_ERR(bo)); + drm_err(&xe->drm, "Failed to prepare %uKiB BO for SA manager (%pe)\n", + size / SZ_1K, bo); return ERR_CAST(bo); } sa_manager->bo = bo; From 7e937cdf18164ea276ce0f4bbc5755e0031280e0 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:41:57 +0100 Subject: [PATCH 024/130] drm/xe/sa: Tidy up coding style in init() There is no need to use tile_to_xe() since we already got the xe. And we should keep all variable declarations together, no need for separate sa_manager declaration. Signed-off-by: Michal Wajdeczko Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-5-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_sa.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c index 0b87599759d7e..0e78ae46667ee 100644 --- a/drivers/gpu/drm/xe/xe_sa.c +++ b/drivers/gpu/drm/xe/xe_sa.c @@ -34,13 +34,12 @@ static void xe_sa_bo_manager_fini(struct drm_device *drm, void *arg) struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 align) { struct xe_device *xe = tile_to_xe(tile); + struct xe_sa_manager *sa_manager; u32 managed_size = size - SZ_4K; struct xe_bo *bo; int ret; - struct xe_sa_manager *sa_manager = drmm_kzalloc(&tile_to_xe(tile)->drm, - sizeof(*sa_manager), - GFP_KERNEL); + sa_manager = drmm_kzalloc(&xe->drm, sizeof(*sa_manager), GFP_KERNEL); if (!sa_manager) return ERR_PTR(-ENOMEM); From 0e1871f61e71d7611196b04d1b133f18fef666dd Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:41:58 +0100 Subject: [PATCH 025/130] drm/xe/sa: Allow making suballocations using custom gfp flags Actual xe_sa_manager implementation uses hardcoded GFP_KERNEL flag during creation of suballocations but in upcoming patch we want to reuse the xe_sa_manager in places where GFP_KERNEL is not allowed. Add another variant of the xe_sa_bo_new() function that accepts arbitrary gfp flags. Signed-off-by: Michal Wajdeczko Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-6-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_sa.c | 15 ++++++++++++--- drivers/gpu/drm/xe/xe_sa.h | 19 +++++++++++++++++-- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c index 0e78ae46667ee..5f89e32b06402 100644 --- a/drivers/gpu/drm/xe/xe_sa.c +++ b/drivers/gpu/drm/xe/xe_sa.c @@ -74,8 +74,17 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 return sa_manager; } -struct drm_suballoc *xe_sa_bo_new(struct xe_sa_manager *sa_manager, - unsigned int size) +/** + * __xe_sa_bo_new() - Make a suballocation but use custom gfp flags. + * @sa_manager: the &xe_sa_manager + * @size: number of bytes we want to suballocate + * @gfp: gfp flags used for memory allocation. Typically GFP_KERNEL. + * + * Try to make a suballocation of size @size. + * + * Return: a &drm_suballoc, or an ERR_PTR. + */ +struct drm_suballoc *__xe_sa_bo_new(struct xe_sa_manager *sa_manager, u32 size, gfp_t gfp) { /* * BB to large, return -ENOBUFS indicating user should split @@ -84,7 +93,7 @@ struct drm_suballoc *xe_sa_bo_new(struct xe_sa_manager *sa_manager, if (size > sa_manager->base.size) return ERR_PTR(-ENOBUFS); - return drm_suballoc_new(&sa_manager->base, size, GFP_KERNEL, true, 0); + return drm_suballoc_new(&sa_manager->base, size, gfp, true, 0); } void xe_sa_bo_flush_write(struct drm_suballoc *sa_bo) diff --git a/drivers/gpu/drm/xe/xe_sa.h b/drivers/gpu/drm/xe/xe_sa.h index 4e96483057d70..a0341eafbe770 100644 --- a/drivers/gpu/drm/xe/xe_sa.h +++ b/drivers/gpu/drm/xe/xe_sa.h @@ -5,6 +5,7 @@ #ifndef _XE_SA_H_ #define _XE_SA_H_ +#include #include "xe_sa_types.h" struct dma_fence; @@ -13,8 +14,22 @@ struct xe_tile; struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 align); -struct drm_suballoc *xe_sa_bo_new(struct xe_sa_manager *sa_manager, - u32 size); +struct drm_suballoc *__xe_sa_bo_new(struct xe_sa_manager *sa_manager, u32 size, gfp_t gfp); + +/** + * xe_sa_bo_new() - Make a suballocation. + * @sa_manager: the &xe_sa_manager + * @size: number of bytes we want to suballocate + * + * Try to make a suballocation of size @size. + * + * Return: a &drm_suballoc, or an ERR_PTR. + */ +static inline struct drm_suballoc *xe_sa_bo_new(struct xe_sa_manager *sa_manager, u32 size) +{ + return __xe_sa_bo_new(sa_manager, size, GFP_KERNEL); +} + void xe_sa_bo_flush_write(struct drm_suballoc *sa_bo); void xe_sa_bo_free(struct drm_suballoc *sa_bo, struct dma_fence *fence); From ae8b507fb8bbea2aa30783184d5728b14ce40c8f Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:41:59 +0100 Subject: [PATCH 026/130] drm/xe/sa: Allow creating suballocator with custom guard size Actual xe_sa_manager implementation uses hardcoded 4K to exclude it from making suballocations but in upcoming patch we want to reuse the xe_sa_manager where such 4K guard is not needed. Add another variant of the xe_sa_bo_manager_init() function that accepts arbitrary guard size. Signed-off-by: Michal Wajdeczko Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-7-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_sa.c | 18 ++++++++++++++++-- drivers/gpu/drm/xe/xe_sa.h | 9 +++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_sa.c b/drivers/gpu/drm/xe/xe_sa.c index 5f89e32b06402..f8fe61e255188 100644 --- a/drivers/gpu/drm/xe/xe_sa.c +++ b/drivers/gpu/drm/xe/xe_sa.c @@ -31,14 +31,28 @@ static void xe_sa_bo_manager_fini(struct drm_device *drm, void *arg) sa_manager->bo = NULL; } -struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 align) +/** + * __xe_sa_bo_manager_init() - Create and initialize the suballocator + * @tile: the &xe_tile where allocate + * @size: number of bytes to allocate + * @guard: number of bytes to exclude from suballocations + * @align: alignment for each suballocated chunk + * + * Prepares the suballocation manager for suballocations. + * + * Return: a pointer to the &xe_sa_manager or an ERR_PTR on failure. + */ +struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 guard, u32 align) { struct xe_device *xe = tile_to_xe(tile); struct xe_sa_manager *sa_manager; - u32 managed_size = size - SZ_4K; + u32 managed_size; struct xe_bo *bo; int ret; + xe_tile_assert(tile, size > guard); + managed_size = size - guard; + sa_manager = drmm_kzalloc(&xe->drm, sizeof(*sa_manager), GFP_KERNEL); if (!sa_manager) return ERR_PTR(-ENOMEM); diff --git a/drivers/gpu/drm/xe/xe_sa.h b/drivers/gpu/drm/xe/xe_sa.h index a0341eafbe770..de0330eb36d49 100644 --- a/drivers/gpu/drm/xe/xe_sa.h +++ b/drivers/gpu/drm/xe/xe_sa.h @@ -5,6 +5,7 @@ #ifndef _XE_SA_H_ #define _XE_SA_H_ +#include #include #include "xe_sa_types.h" @@ -12,10 +13,14 @@ struct dma_fence; struct xe_bo; struct xe_tile; -struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 align); - +struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 guard, u32 align); struct drm_suballoc *__xe_sa_bo_new(struct xe_sa_manager *sa_manager, u32 size, gfp_t gfp); +static inline struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 align) +{ + return __xe_sa_bo_manager_init(tile, size, SZ_4K, align); +} + /** * xe_sa_bo_new() - Make a suballocation. * @sa_manager: the &xe_sa_manager From c49ca671818a325f2221f0bda8af96e339272a5e Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:42:00 +0100 Subject: [PATCH 027/130] drm/xe/sa: Minor header cleanups Drop unused struct xe_bo forward declaration and, while around, fix unnecessary line split in xe_sa_bo_free() declaration. Signed-off-by: Michal Wajdeczko Cc: Matthew Brost Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-8-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_sa.h | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_sa.h b/drivers/gpu/drm/xe/xe_sa.h index de0330eb36d49..1170ee5a81a82 100644 --- a/drivers/gpu/drm/xe/xe_sa.h +++ b/drivers/gpu/drm/xe/xe_sa.h @@ -10,7 +10,6 @@ #include "xe_sa_types.h" struct dma_fence; -struct xe_bo; struct xe_tile; struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 guard, u32 align); @@ -36,8 +35,7 @@ static inline struct drm_suballoc *xe_sa_bo_new(struct xe_sa_manager *sa_manager } void xe_sa_bo_flush_write(struct drm_suballoc *sa_bo); -void xe_sa_bo_free(struct drm_suballoc *sa_bo, - struct dma_fence *fence); +void xe_sa_bo_free(struct drm_suballoc *sa_bo, struct dma_fence *fence); static inline struct xe_sa_manager * to_xe_sa_manager(struct drm_suballoc_manager *mng) From 696bfdf273eab9ce3dd2ff51d26ca30f7924a4bb Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:42:01 +0100 Subject: [PATCH 028/130] drm/xe/guc: Introduce the GuC Buffer Cache The purpose of the GuC Buffer Cache is to maintain a set ofreusable buffers that could be used while sending some of the CTB H2G actions that require separate buffer with indirect data. Currently only few PF actions need this so initialize it only when running as a PF. Signed-off-by: Michal Wajdeczko Cc: Matthew Brost Cc: Rodrigo Vivi Acked-by: Rodrigo Vivi Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-9-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_guc.c | 5 + drivers/gpu/drm/xe/xe_guc_buf.c | 172 ++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_guc_buf.h | 47 +++++++ drivers/gpu/drm/xe/xe_guc_buf_types.h | 28 +++++ drivers/gpu/drm/xe/xe_guc_types.h | 3 + 6 files changed, 256 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_guc_buf.c create mode 100644 drivers/gpu/drm/xe/xe_guc_buf.h create mode 100644 drivers/gpu/drm/xe/xe_guc_buf_types.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 7730e0596299e..2e50a697f5494 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -56,6 +56,7 @@ xe-y += xe_bb.o \ xe_gt_topology.o \ xe_guc.o \ xe_guc_ads.o \ + xe_guc_buf.o \ xe_guc_capture.o \ xe_guc_ct.o \ xe_guc_db_mgr.o \ diff --git a/drivers/gpu/drm/xe/xe_guc.c b/drivers/gpu/drm/xe/xe_guc.c index 408365dfe4eed..1619c0a52db93 100644 --- a/drivers/gpu/drm/xe/xe_guc.c +++ b/drivers/gpu/drm/xe/xe_guc.c @@ -23,6 +23,7 @@ #include "xe_gt_sriov_vf.h" #include "xe_gt_throttle.h" #include "xe_guc_ads.h" +#include "xe_guc_buf.h" #include "xe_guc_capture.h" #include "xe_guc_ct.h" #include "xe_guc_db_mgr.h" @@ -743,6 +744,10 @@ int xe_guc_init_post_hwconfig(struct xe_guc *guc) if (ret) return ret; + ret = xe_guc_buf_cache_init(&guc->buf); + if (ret) + return ret; + return xe_guc_ads_init_post_hwconfig(&guc->ads); } diff --git a/drivers/gpu/drm/xe/xe_guc_buf.c b/drivers/gpu/drm/xe/xe_guc_buf.c new file mode 100644 index 0000000000000..261c7c74417fe --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_buf.c @@ -0,0 +1,172 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2024 Intel Corporation + */ + +#include +#include + +#include "xe_assert.h" +#include "xe_bo.h" +#include "xe_gt_printk.h" +#include "xe_guc.h" +#include "xe_guc_buf.h" +#include "xe_sa.h" + +static struct xe_guc *cache_to_guc(struct xe_guc_buf_cache *cache) +{ + return container_of(cache, struct xe_guc, buf); +} + +static struct xe_gt *cache_to_gt(struct xe_guc_buf_cache *cache) +{ + return guc_to_gt(cache_to_guc(cache)); +} + +/** + * xe_guc_buf_cache_init() - Initialize the GuC Buffer Cache. + * @cache: the &xe_guc_buf_cache to initialize + * + * The Buffer Cache allows to obtain a reusable buffer that can be used to pass + * indirect H2G data to GuC without a need to create a ad-hoc allocation. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_guc_buf_cache_init(struct xe_guc_buf_cache *cache) +{ + struct xe_gt *gt = cache_to_gt(cache); + struct xe_sa_manager *sam; + + /* XXX: currently it's useful only for the PF actions */ + if (!IS_SRIOV_PF(gt_to_xe(gt))) + return 0; + + sam = __xe_sa_bo_manager_init(gt_to_tile(gt), SZ_8K, 0, sizeof(u32)); + if (IS_ERR(sam)) + return PTR_ERR(sam); + cache->sam = sam; + + xe_gt_dbg(gt, "reusable buffer with %u dwords at %#x for %ps\n", + xe_guc_buf_cache_dwords(cache), xe_bo_ggtt_addr(sam->bo), + __builtin_return_address(0)); + return 0; +} + +/** + * xe_guc_buf_cache_dwords() - Number of dwords the GuC Buffer Cache supports. + * @cache: the &xe_guc_buf_cache to query + * + * Return: a size of the largest reusable buffer (in dwords) + */ +u32 xe_guc_buf_cache_dwords(struct xe_guc_buf_cache *cache) +{ + return cache->sam ? cache->sam->base.size / sizeof(u32) : 0; +} + +/** + * xe_guc_buf_reserve() - Reserve a new sub-allocation. + * @cache: the &xe_guc_buf_cache where reserve sub-allocation + * @dwords: the requested size of the buffer in dwords + * + * Use xe_guc_buf_is_valid() to check if returned buffer reference is valid. + * Must use xe_guc_buf_release() to release a sub-allocation. + * + * Return: a &xe_guc_buf of new sub-allocation. + */ +struct xe_guc_buf xe_guc_buf_reserve(struct xe_guc_buf_cache *cache, u32 dwords) +{ + struct drm_suballoc *sa; + + if (cache->sam) + sa = __xe_sa_bo_new(cache->sam, dwords * sizeof(32), GFP_ATOMIC); + else + sa = ERR_PTR(-EOPNOTSUPP); + + return (struct xe_guc_buf){ .sa = sa }; +} + +/** + * xe_guc_buf_from_data() - Reserve a new sub-allocation using data. + * @cache: the &xe_guc_buf_cache where reserve sub-allocation + * @data: the data to flush the sub-allocation + * @size: the size of the data + * + * Similar to xe_guc_buf_reserve() but flushes @data to the GPU memory. + * + * Return: a &xe_guc_buf of new sub-allocation. + */ +struct xe_guc_buf xe_guc_buf_from_data(struct xe_guc_buf_cache *cache, + const void *data, size_t size) +{ + struct drm_suballoc *sa; + + sa = __xe_sa_bo_new(cache->sam, size, GFP_ATOMIC); + if (!IS_ERR(sa)) + memcpy(xe_sa_bo_cpu_addr(sa), data, size); + + return (struct xe_guc_buf){ .sa = sa }; +} + +/** + * xe_guc_buf_release() - Release a sub-allocation. + * @buf: the &xe_guc_buf to release + * + * Releases a sub-allocation reserved by the xe_guc_buf_reserve(). + */ +void xe_guc_buf_release(const struct xe_guc_buf buf) +{ + if (xe_guc_buf_is_valid(buf)) + xe_sa_bo_free(buf.sa, NULL); +} + +/** + * xe_guc_buf_flush() - Copy the data from the sub-allocation to the GPU memory. + * @buf: the &xe_guc_buf to flush + * + * Return: a GPU address of the sub-allocation. + */ +u64 xe_guc_buf_flush(const struct xe_guc_buf buf) +{ + xe_sa_bo_flush_write(buf.sa); + return xe_sa_bo_gpu_addr(buf.sa); +} + +/** + * xe_guc_buf_cpu_ptr() - Obtain a CPU pointer to the sub-allocation. + * @buf: the &xe_guc_buf to query + * + * Return: a CPU pointer of the sub-allocation. + */ +void *xe_guc_buf_cpu_ptr(const struct xe_guc_buf buf) +{ + return xe_sa_bo_cpu_addr(buf.sa); +} + +/** + * xe_guc_buf_gpu_addr() - Obtain a GPU address of the sub-allocation. + * @buf: the &xe_guc_buf to query + * + * Return: a GPU address of the sub-allocation. + */ +u64 xe_guc_buf_gpu_addr(const struct xe_guc_buf buf) +{ + return xe_sa_bo_gpu_addr(buf.sa); +} + +/** + * xe_guc_cache_gpu_addr_from_ptr() - Lookup a GPU address using the pointer. + * @cache: the &xe_guc_buf_cache with sub-allocations + * @ptr: the CPU pointer of the sub-allocation + * @size: the size of the data + * + * Return: a GPU address on success or 0 if the pointer was unrelated. + */ +u64 xe_guc_cache_gpu_addr_from_ptr(struct xe_guc_buf_cache *cache, const void *ptr, u32 size) +{ + ptrdiff_t offset = ptr - cache->sam->cpu_ptr; + + if (offset < 0 || offset + size > cache->sam->base.size) + return 0; + + return cache->sam->gpu_addr + offset; +} diff --git a/drivers/gpu/drm/xe/xe_guc_buf.h b/drivers/gpu/drm/xe/xe_guc_buf.h new file mode 100644 index 0000000000000..0d67604d96bdd --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_buf.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2024 Intel Corporation + */ + +#ifndef _XE_GUC_BUF_H_ +#define _XE_GUC_BUF_H_ + +#include +#include + +#include "xe_guc_buf_types.h" + +int xe_guc_buf_cache_init(struct xe_guc_buf_cache *cache); +u32 xe_guc_buf_cache_dwords(struct xe_guc_buf_cache *cache); +struct xe_guc_buf xe_guc_buf_reserve(struct xe_guc_buf_cache *cache, u32 dwords); +struct xe_guc_buf xe_guc_buf_from_data(struct xe_guc_buf_cache *cache, + const void *data, size_t size); +void xe_guc_buf_release(const struct xe_guc_buf buf); + +/** + * xe_guc_buf_is_valid() - Check if a buffer reference is valid. + * @buf: the &xe_guc_buf reference to check + * + * Return: true if @ref represents a valid sub-allication. + */ +static inline bool xe_guc_buf_is_valid(const struct xe_guc_buf buf) +{ + return !IS_ERR_OR_NULL(buf.sa); +} + +void *xe_guc_buf_cpu_ptr(const struct xe_guc_buf buf); +u64 xe_guc_buf_flush(const struct xe_guc_buf buf); +u64 xe_guc_buf_gpu_addr(const struct xe_guc_buf buf); +u64 xe_guc_cache_gpu_addr_from_ptr(struct xe_guc_buf_cache *cache, const void *ptr, u32 size); + +DEFINE_CLASS(xe_guc_buf, struct xe_guc_buf, + xe_guc_buf_release(_T), + xe_guc_buf_reserve(cache, num), + struct xe_guc_buf_cache *cache, u32 num); + +DEFINE_CLASS(xe_guc_buf_from_data, struct xe_guc_buf, + xe_guc_buf_release(_T), + xe_guc_buf_from_data(cache, data, size), + struct xe_guc_buf_cache *cache, const void *data, size_t size); + +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_buf_types.h b/drivers/gpu/drm/xe/xe_guc_buf_types.h new file mode 100644 index 0000000000000..9e123d71c064a --- /dev/null +++ b/drivers/gpu/drm/xe/xe_guc_buf_types.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2024 Intel Corporation + */ + +#ifndef _XE_GUC_BUF_TYPES_H_ +#define _XE_GUC_BUF_TYPES_H_ + +struct drm_suballoc; +struct xe_sa_manager; + +/** + * struct xe_guc_buf_cache - GuC Data Buffer Cache. + */ +struct xe_guc_buf_cache { + /* private: internal sub-allocation manager */ + struct xe_sa_manager *sam; +}; + +/** + * struct xe_guc_buf - GuC Data Buffer Reference. + */ +struct xe_guc_buf { + /* private: internal sub-allocation reference */ + struct drm_suballoc *sa; +}; + +#endif diff --git a/drivers/gpu/drm/xe/xe_guc_types.h b/drivers/gpu/drm/xe/xe_guc_types.h index 83a41ebcdc91d..573aa6308380a 100644 --- a/drivers/gpu/drm/xe/xe_guc_types.h +++ b/drivers/gpu/drm/xe/xe_guc_types.h @@ -11,6 +11,7 @@ #include "regs/xe_reg_defs.h" #include "xe_guc_ads_types.h" +#include "xe_guc_buf_types.h" #include "xe_guc_ct_types.h" #include "xe_guc_fwif.h" #include "xe_guc_log_types.h" @@ -58,6 +59,8 @@ struct xe_guc { struct xe_guc_ads ads; /** @ct: GuC ct */ struct xe_guc_ct ct; + /** @buf: GuC Buffer Cache manager */ + struct xe_guc_buf_cache buf; /** @capture: the error-state-capture module's data and objects */ struct xe_guc_state_capture *capture; /** @pc: GuC Power Conservation */ From d8b2149ba8f184cd138b482289b16d8558787e99 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:42:02 +0100 Subject: [PATCH 029/130] drm/xe/pf: Use GuC Buffer Cache during VFs provisioning Start using GuC buffer cache for the VF's configuration actions. Signed-off-by: Michal Wajdeczko Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-10-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 68 +++++++++++----------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index 878e96281c035..9db1c920219da 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -20,6 +20,7 @@ #include "xe_gt_sriov_pf_policy.h" #include "xe_gt_sriov_printk.h" #include "xe_guc.h" +#include "xe_guc_buf.h" #include "xe_guc_ct.h" #include "xe_guc_db_mgr.h" #include "xe_guc_fwif.h" @@ -71,48 +72,27 @@ static int pf_send_vf_cfg_reset(struct xe_gt *gt, u32 vfid) * Return: number of KLVs that were successfully parsed and saved, * negative error code on failure. */ -static int pf_send_vf_cfg_klvs(struct xe_gt *gt, u32 vfid, const u32 *klvs, u32 num_dwords) +static int pf_send_vf_buf_klvs(struct xe_gt *gt, u32 vfid, struct xe_guc_buf buf, u32 num_dwords) { - const u32 bytes = num_dwords * sizeof(u32); - struct xe_tile *tile = gt_to_tile(gt); - struct xe_device *xe = tile_to_xe(tile); struct xe_guc *guc = >->uc.guc; - struct xe_bo *bo; - int ret; - bo = xe_bo_create_pin_map(xe, tile, NULL, - ALIGN(bytes, PAGE_SIZE), - ttm_bo_type_kernel, - XE_BO_FLAG_VRAM_IF_DGFX(tile) | - XE_BO_FLAG_GGTT | - XE_BO_FLAG_GGTT_INVALIDATE); - if (IS_ERR(bo)) - return PTR_ERR(bo); - - xe_map_memcpy_to(xe, &bo->vmap, 0, klvs, bytes); - - ret = guc_action_update_vf_cfg(guc, vfid, xe_bo_ggtt_addr(bo), num_dwords); - - xe_bo_unpin_map_no_vm(bo); - - return ret; + return guc_action_update_vf_cfg(guc, vfid, xe_guc_buf_flush(buf), num_dwords); } /* * Return: 0 on success, -ENOKEY if some KLVs were not updated, -EPROTO if reply was malformed, * negative error code on failure. */ -static int pf_push_vf_cfg_klvs(struct xe_gt *gt, unsigned int vfid, u32 num_klvs, - const u32 *klvs, u32 num_dwords) +static int pf_push_vf_buf_klvs(struct xe_gt *gt, unsigned int vfid, u32 num_klvs, + struct xe_guc_buf buf, u32 num_dwords) { int ret; - xe_gt_assert(gt, num_klvs == xe_guc_klv_count(klvs, num_dwords)); - - ret = pf_send_vf_cfg_klvs(gt, vfid, klvs, num_dwords); + ret = pf_send_vf_buf_klvs(gt, vfid, buf, num_dwords); if (ret != num_klvs) { int err = ret < 0 ? ret : ret < num_klvs ? -ENOKEY : -EPROTO; + void *klvs = xe_guc_buf_cpu_ptr(buf); struct drm_printer p = xe_gt_info_printer(gt); char name[8]; @@ -125,13 +105,35 @@ static int pf_push_vf_cfg_klvs(struct xe_gt *gt, unsigned int vfid, u32 num_klvs if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV)) { struct drm_printer p = xe_gt_info_printer(gt); + void *klvs = xe_guc_buf_cpu_ptr(buf); + char name[8]; + xe_gt_sriov_info(gt, "pushed %s config with %u KLV%s:\n", + xe_sriov_function_name(vfid, name, sizeof(name)), + num_klvs, str_plural(num_klvs)); xe_guc_klv_print(klvs, num_dwords, &p); } return 0; } +/* + * Return: 0 on success, -ENOBUFS if no free buffer for the indirect data, + * negative error code on failure. + */ +static int pf_push_vf_cfg_klvs(struct xe_gt *gt, unsigned int vfid, u32 num_klvs, + const u32 *klvs, u32 num_dwords) +{ + CLASS(xe_guc_buf_from_data, buf)(>->uc.guc.buf, klvs, num_dwords * sizeof(u32)); + + xe_gt_assert(gt, num_klvs == xe_guc_klv_count(klvs, num_dwords)); + + if (!xe_guc_buf_is_valid(buf)) + return -ENOBUFS; + + return pf_push_vf_buf_klvs(gt, vfid, num_klvs, buf, num_dwords); +} + static int pf_push_vf_cfg_u32(struct xe_gt *gt, unsigned int vfid, u16 key, u32 value) { u32 klv[] = { @@ -304,16 +306,17 @@ static u32 encode_config(u32 *cfg, const struct xe_gt_sriov_config *config, bool static int pf_push_full_vf_config(struct xe_gt *gt, unsigned int vfid) { struct xe_gt_sriov_config *config = pf_pick_vf_config(gt, vfid); - u32 max_cfg_dwords = SZ_4K / sizeof(u32); + u32 max_cfg_dwords = xe_guc_buf_cache_dwords(>->uc.guc.buf); + CLASS(xe_guc_buf, buf)(>->uc.guc.buf, max_cfg_dwords); u32 num_dwords; int num_klvs; u32 *cfg; int err; - cfg = kcalloc(max_cfg_dwords, sizeof(u32), GFP_KERNEL); - if (!cfg) - return -ENOMEM; + if (!xe_guc_buf_is_valid(buf)) + return -ENOBUFS; + cfg = xe_guc_buf_cpu_ptr(buf); num_dwords = encode_config(cfg, config, true); xe_gt_assert(gt, num_dwords <= max_cfg_dwords); @@ -330,9 +333,8 @@ static int pf_push_full_vf_config(struct xe_gt *gt, unsigned int vfid) xe_gt_assert(gt, num_dwords <= max_cfg_dwords); num_klvs = xe_guc_klv_count(cfg, num_dwords); - err = pf_push_vf_cfg_klvs(gt, vfid, num_klvs, cfg, num_dwords); + err = pf_push_vf_buf_klvs(gt, vfid, num_klvs, buf, num_dwords); - kfree(cfg); return err; } From f90b552dcbb4e142f2a15d2b4458ea601248b8e8 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 20 Dec 2024 20:42:03 +0100 Subject: [PATCH 030/130] drm/xe/kunit: Allow to replace xe_managed_bo_create_pin_map() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to use replacement functions in upcoming kunit tests. Signed-off-by: Michal Wajdeczko Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20241220194205.995-11-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_bo.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index cf0dc9e9c53eb..c32201123d448 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -15,6 +15,8 @@ #include #include +#include + #include "xe_device.h" #include "xe_dma_buf.h" #include "xe_drm_client.h" @@ -1797,6 +1799,8 @@ struct xe_bo *xe_managed_bo_create_pin_map(struct xe_device *xe, struct xe_tile struct xe_bo *bo; int ret; + KUNIT_STATIC_STUB_REDIRECT(xe_managed_bo_create_pin_map, xe, tile, size, flags); + bo = xe_bo_create_pin_map(xe, tile, NULL, size, ttm_bo_type_kernel, flags); if (IS_ERR(bo)) return bo; From 238f96315ada9e2183b04df90c9714b1da68455c Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 14 Jan 2025 20:21:40 +0100 Subject: [PATCH 031/130] drm/xe/kunit: Add KUnit tests for GuC Buffer Cache MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add tests to make sure that recently added GuC Buffer Cache component is working as expected. Signed-off-by: Michal Wajdeczko Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20250114192140.1039-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c | 334 ++++++++++++++++++++ drivers/gpu/drm/xe/xe_guc_buf.c | 4 + 2 files changed, 338 insertions(+) create mode 100644 drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c diff --git a/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c b/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c new file mode 100644 index 0000000000000..6faffcd748694 --- /dev/null +++ b/drivers/gpu/drm/xe/tests/xe_guc_buf_kunit.c @@ -0,0 +1,334 @@ +// SPDX-License-Identifier: GPL-2.0 AND MIT +/* + * Copyright © 2024 Intel Corporation + */ + +#include +#include +#include + +#include "xe_device.h" +#include "xe_ggtt.h" +#include "xe_guc_ct.h" +#include "xe_kunit_helpers.h" +#include "xe_pci_test.h" + +#define DUT_GGTT_START SZ_1M +#define DUT_GGTT_SIZE SZ_2M + +static struct xe_bo *replacement_xe_managed_bo_create_pin_map(struct xe_device *xe, + struct xe_tile *tile, + size_t size, u32 flags) +{ + struct kunit *test = kunit_get_current_test(); + struct xe_bo *bo; + void *buf; + + bo = drmm_kzalloc(&xe->drm, sizeof(*bo), GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo); + + buf = drmm_kzalloc(&xe->drm, size, GFP_KERNEL); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf); + + bo->tile = tile; + bo->ttm.bdev = &xe->ttm; + bo->size = size; + iosys_map_set_vaddr(&bo->vmap, buf); + + if (flags & XE_BO_FLAG_GGTT) { + struct xe_ggtt *ggtt = tile->mem.ggtt; + + bo->ggtt_node[tile->id] = xe_ggtt_node_init(ggtt); + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo->ggtt_node[tile->id]); + + KUNIT_ASSERT_EQ(test, 0, + drm_mm_insert_node_in_range(&ggtt->mm, + &bo->ggtt_node[tile->id]->base, + bo->size, SZ_4K, + 0, 0, U64_MAX, 0)); + } + + return bo; +} + +static int guc_buf_test_init(struct kunit *test) +{ + struct xe_pci_fake_data fake = { + .sriov_mode = XE_SRIOV_MODE_PF, + .platform = XE_TIGERLAKE, /* some random platform */ + .subplatform = XE_SUBPLATFORM_NONE, + }; + struct xe_ggtt *ggtt; + struct xe_guc *guc; + + test->priv = &fake; + xe_kunit_helper_xe_device_test_init(test); + + ggtt = xe_device_get_root_tile(test->priv)->mem.ggtt; + guc = &xe_device_get_gt(test->priv, 0)->uc.guc; + + drm_mm_init(&ggtt->mm, DUT_GGTT_START, DUT_GGTT_SIZE); + mutex_init(&ggtt->lock); + + kunit_activate_static_stub(test, xe_managed_bo_create_pin_map, + replacement_xe_managed_bo_create_pin_map); + + KUNIT_ASSERT_EQ(test, 0, xe_guc_buf_cache_init(&guc->buf)); + + test->priv = &guc->buf; + return 0; +} + +static void test_smallest(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf buf; + + buf = xe_guc_buf_reserve(cache, 1); + KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf)); + KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf)); + KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf)); + KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf)); + KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf)); + xe_guc_buf_release(buf); +} + +static void test_largest(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf buf; + + buf = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache)); + KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf)); + KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf)); + KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf)); + KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf)); + KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf)); + xe_guc_buf_release(buf); +} + +static void test_granular(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf *bufs; + int n, dwords; + + dwords = xe_guc_buf_cache_dwords(cache); + bufs = kunit_kcalloc(test, dwords, sizeof(*bufs), GFP_KERNEL); + KUNIT_EXPECT_NOT_NULL(test, bufs); + + for (n = 0; n < dwords; n++) + bufs[n] = xe_guc_buf_reserve(cache, 1); + + for (n = 0; n < dwords; n++) + KUNIT_EXPECT_TRUE_MSG(test, xe_guc_buf_is_valid(bufs[n]), "n=%d", n); + + for (n = 0; n < dwords; n++) + xe_guc_buf_release(bufs[n]); +} + +static void test_unique(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf *bufs; + int n, m, dwords; + + dwords = xe_guc_buf_cache_dwords(cache); + bufs = kunit_kcalloc(test, dwords, sizeof(*bufs), GFP_KERNEL); + KUNIT_EXPECT_NOT_NULL(test, bufs); + + for (n = 0; n < dwords; n++) + bufs[n] = xe_guc_buf_reserve(cache, 1); + + for (n = 0; n < dwords; n++) { + for (m = n + 1; m < dwords; m++) { + KUNIT_EXPECT_PTR_NE_MSG(test, xe_guc_buf_cpu_ptr(bufs[n]), + xe_guc_buf_cpu_ptr(bufs[m]), "n=%d, m=%d", n, m); + KUNIT_ASSERT_NE_MSG(test, xe_guc_buf_gpu_addr(bufs[n]), + xe_guc_buf_gpu_addr(bufs[m]), "n=%d, m=%d", n, m); + } + } + + for (n = 0; n < dwords; n++) + xe_guc_buf_release(bufs[n]); +} + +static void test_overlap(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf b1, b2; + u32 dwords = xe_guc_buf_cache_dwords(cache) / 2; + u32 bytes = dwords * sizeof(u32); + void *p1, *p2; + u64 a1, a2; + + b1 = xe_guc_buf_reserve(cache, dwords); + b2 = xe_guc_buf_reserve(cache, dwords); + + p1 = xe_guc_buf_cpu_ptr(b1); + p2 = xe_guc_buf_cpu_ptr(b2); + + a1 = xe_guc_buf_gpu_addr(b1); + a2 = xe_guc_buf_gpu_addr(b2); + + KUNIT_EXPECT_PTR_NE(test, p1, p2); + if (p1 < p2) + KUNIT_EXPECT_LT(test, (uintptr_t)(p1 + bytes - 1), (uintptr_t)p2); + else + KUNIT_EXPECT_LT(test, (uintptr_t)(p2 + bytes - 1), (uintptr_t)p1); + + KUNIT_EXPECT_NE(test, a1, a2); + if (a1 < a2) + KUNIT_EXPECT_LT(test, a1 + bytes - 1, a2); + else + KUNIT_EXPECT_LT(test, a2 + bytes - 1, a1); + + xe_guc_buf_release(b1); + xe_guc_buf_release(b2); +} + +static void test_reusable(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf b1, b2; + void *p1; + u64 a1; + + b1 = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache)); + KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(b1)); + KUNIT_EXPECT_NOT_NULL(test, p1 = xe_guc_buf_cpu_ptr(b1)); + KUNIT_EXPECT_NE(test, 0, a1 = xe_guc_buf_gpu_addr(b1)); + xe_guc_buf_release(b1); + + b2 = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache)); + KUNIT_EXPECT_PTR_EQ(test, p1, xe_guc_buf_cpu_ptr(b2)); + KUNIT_EXPECT_EQ(test, a1, xe_guc_buf_gpu_addr(b2)); + xe_guc_buf_release(b2); +} + +static void test_too_big(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf buf; + + buf = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache) + 1); + KUNIT_EXPECT_FALSE(test, xe_guc_buf_is_valid(buf)); + xe_guc_buf_release(buf); /* shouldn't crash */ +} + +static void test_flush(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf buf; + const u32 dwords = xe_guc_buf_cache_dwords(cache); + const u32 bytes = dwords * sizeof(u32); + u32 *s, *p, *d; + int n; + + KUNIT_ASSERT_NOT_NULL(test, s = kunit_kcalloc(test, dwords, sizeof(u32), GFP_KERNEL)); + KUNIT_ASSERT_NOT_NULL(test, d = kunit_kcalloc(test, dwords, sizeof(u32), GFP_KERNEL)); + + for (n = 0; n < dwords; n++) + s[n] = n; + + buf = xe_guc_buf_reserve(cache, dwords); + KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf)); + KUNIT_ASSERT_NOT_NULL(test, p = xe_guc_buf_cpu_ptr(buf)); + KUNIT_EXPECT_PTR_NE(test, p, s); + KUNIT_EXPECT_PTR_NE(test, p, d); + + memcpy(p, s, bytes); + KUNIT_EXPECT_NE(test, 0, xe_guc_buf_flush(buf)); + + iosys_map_memcpy_from(d, &cache->sam->bo->vmap, 0, bytes); + KUNIT_EXPECT_MEMEQ(test, s, d, bytes); + + xe_guc_buf_release(buf); +} + +static void test_lookup(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf buf; + u32 dwords; + u64 addr; + u32 *p; + int n; + + dwords = xe_guc_buf_cache_dwords(cache); + buf = xe_guc_buf_reserve(cache, dwords); + KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf)); + KUNIT_ASSERT_NOT_NULL(test, p = xe_guc_buf_cpu_ptr(buf)); + KUNIT_ASSERT_NE(test, 0, addr = xe_guc_buf_gpu_addr(buf)); + + KUNIT_EXPECT_EQ(test, 0, xe_guc_cache_gpu_addr_from_ptr(cache, p - 1, sizeof(u32))); + KUNIT_EXPECT_EQ(test, 0, xe_guc_cache_gpu_addr_from_ptr(cache, p + dwords, sizeof(u32))); + + for (n = 0; n < dwords; n++) + KUNIT_EXPECT_EQ_MSG(test, xe_guc_cache_gpu_addr_from_ptr(cache, p + n, sizeof(u32)), + addr + n * sizeof(u32), "n=%d", n); + + xe_guc_buf_release(buf); +} + +static void test_data(struct kunit *test) +{ + static const u32 data[] = { 1, 2, 3, 4, 5, 6 }; + struct xe_guc_buf_cache *cache = test->priv; + struct xe_guc_buf buf; + void *p; + + buf = xe_guc_buf_from_data(cache, data, sizeof(data)); + KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf)); + KUNIT_ASSERT_NOT_NULL(test, p = xe_guc_buf_cpu_ptr(buf)); + KUNIT_EXPECT_MEMEQ(test, p, data, sizeof(data)); + + xe_guc_buf_release(buf); +} + +static void test_class(struct kunit *test) +{ + struct xe_guc_buf_cache *cache = test->priv; + u32 dwords = xe_guc_buf_cache_dwords(cache); + + { + CLASS(xe_guc_buf, buf)(cache, dwords); + KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf)); + KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf)); + KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf)); + KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf)); + KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf)); + } + + { + CLASS(xe_guc_buf, buf)(cache, dwords); + KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf)); + KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf)); + KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf)); + KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf)); + KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf)); + } +} + +static struct kunit_case guc_buf_test_cases[] = { + KUNIT_CASE(test_smallest), + KUNIT_CASE(test_largest), + KUNIT_CASE(test_granular), + KUNIT_CASE(test_unique), + KUNIT_CASE(test_overlap), + KUNIT_CASE(test_reusable), + KUNIT_CASE(test_too_big), + KUNIT_CASE(test_flush), + KUNIT_CASE(test_lookup), + KUNIT_CASE(test_data), + KUNIT_CASE(test_class), + {} +}; + +static struct kunit_suite guc_buf_suite = { + .name = "guc_buf", + .test_cases = guc_buf_test_cases, + .init = guc_buf_test_init, +}; + +kunit_test_suites(&guc_buf_suite); diff --git a/drivers/gpu/drm/xe/xe_guc_buf.c b/drivers/gpu/drm/xe/xe_guc_buf.c index 261c7c74417fe..ce6d9830e13b6 100644 --- a/drivers/gpu/drm/xe/xe_guc_buf.c +++ b/drivers/gpu/drm/xe/xe_guc_buf.c @@ -170,3 +170,7 @@ u64 xe_guc_cache_gpu_addr_from_ptr(struct xe_guc_buf_cache *cache, const void *p return cache->sam->gpu_addr + offset; } + +#if IS_BUILTIN(CONFIG_DRM_XE_KUNIT_TEST) +#include "tests/xe_guc_buf_kunit.c" +#endif From 173baa1b2dc44e3551d9414f4919a48fe5da4880 Mon Sep 17 00:00:00 2001 From: Satyanarayana K V P Date: Thu, 16 Jan 2025 11:26:17 +0530 Subject: [PATCH 032/130] drm/xe: Suppress printing of mode when running in non-sriov mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The xe_sriov_probe_early() function prints the sriov pf/vf mode on driver probe. When running in non-sriov mode, the below debug message is seen. "Running in none mode". This print does not convey any information. This commit suppresses this debug message and shows only when running in PF/VF mode. Signed-off-by: Satyanarayana K V P Cc: Michał Wajdeczko Reviewed-by: Lucas De Marchi Signed-off-by: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/20250116055617.20611-1-satyanarayana.k.v.p@intel.com --- drivers/gpu/drm/xe/xe_sriov.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_sriov.c b/drivers/gpu/drm/xe/xe_sriov.c index 04e2f539ccd94..a0eab44c0e768 100644 --- a/drivers/gpu/drm/xe/xe_sriov.c +++ b/drivers/gpu/drm/xe/xe_sriov.c @@ -81,7 +81,7 @@ void xe_sriov_probe_early(struct xe_device *xe) xe->sriov.__mode = mode; xe_assert(xe, xe->sriov.__mode); - if (has_sriov) + if (IS_SRIOV(xe)) drm_info(&xe->drm, "Running in %s mode\n", xe_sriov_mode_to_string(xe_device_sriov_mode(xe))); } From f3b59457808f61d88178b0afa67cbd017d7ce79e Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 10 Dec 2024 09:31:11 +0100 Subject: [PATCH 033/130] drm/xe: Do not attempt to bootstrap VF in execlists mode It was mentioned in a review that there is a possibility of choosing to load the module with VF in execlists mode. Of course this doesn't work, just bomb out as hard as possible. Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20241210083111.230484-12-dev@lankhorst.se Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/xe/xe_gt_sriov_vf.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c index cca5d57328021..6671030439fd7 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c @@ -213,6 +213,9 @@ int xe_gt_sriov_vf_bootstrap(struct xe_gt *gt) { int err; + if (!xe_device_uc_enabled(gt_to_xe(gt))) + return -ENODEV; + err = vf_reset_guc_state(gt); if (unlikely(err)) return err; From a46ea12eca59fd3741ddfec3042d43f87fadf58f Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 17 Jan 2025 14:38:27 -0500 Subject: [PATCH 034/130] drm/xe/uapi: Fix documentation indentation Fix these issues: Documentation/gpu/driver-uapi:29: include/uapi/drm/xe_drm.h:817: WARNING: +Bullet list ends without a blank line; unexpected unindent. Documentation/gpu/driver-uapi:29: include/uapi/drm/xe_drm.h:835: WARNING: +Definition list ends without a blank line; unexpected unindent. Fixes: 75d37750a753 ("drm/xe/mmap: Add mmap support for PCI memory barrier") Reported-by: Stephen Rothwell Closes: https://lore.kernel.org/intel-xe/20250117164023.3fdc00b9@canb.auug.org.au/ Cc: Tejas Upadhyay Tested-by: Bagas Sanjaya Reviewed-by: Tejas Upadhyay Link: https://patchwork.freedesktop.org/patch/msgid/20250117193827.91779-1-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- include/uapi/drm/xe_drm.h | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index cac607a30f6d3..e2160330ad01f 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -814,29 +814,29 @@ struct drm_xe_gem_create { * * The @flags can be: * - %DRM_XE_MMAP_OFFSET_FLAG_PCI_BARRIER - For user to query special offset - * for use in mmap ioctl. Writing to the returned mmap address will generate a - * PCI memory barrier with low overhead (avoiding IOCTL call as well as writing - * to VRAM which would also add overhead), acting like an MI_MEM_FENCE - * instruction. + * for use in mmap ioctl. Writing to the returned mmap address will generate a + * PCI memory barrier with low overhead (avoiding IOCTL call as well as writing + * to VRAM which would also add overhead), acting like an MI_MEM_FENCE + * instruction. * - * Note: The mmap size can be at most 4K, due to HW limitations. As a result - * this interface is only supported on CPU architectures that support 4K page - * size. The mmap_offset ioctl will detect this and gracefully return an - * error, where userspace is expected to have a different fallback method for - * triggering a barrier. + * Note: The mmap size can be at most 4K, due to HW limitations. As a result + * this interface is only supported on CPU architectures that support 4K page + * size. The mmap_offset ioctl will detect this and gracefully return an + * error, where userspace is expected to have a different fallback method for + * triggering a barrier. * - * Roughly the usage would be as follows: + * Roughly the usage would be as follows: * - * .. code-block:: C + * .. code-block:: C * - * struct drm_xe_gem_mmap_offset mmo = { - * .handle = 0, // must be set to 0 - * .flags = DRM_XE_MMAP_OFFSET_FLAG_PCI_BARRIER, - * }; + * struct drm_xe_gem_mmap_offset mmo = { + * .handle = 0, // must be set to 0 + * .flags = DRM_XE_MMAP_OFFSET_FLAG_PCI_BARRIER, + * }; * - * err = ioctl(fd, DRM_IOCTL_XE_GEM_MMAP_OFFSET, &mmo); - * map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, mmo.offset); - * map[i] = 0xdeadbeaf; // issue barrier + * err = ioctl(fd, DRM_IOCTL_XE_GEM_MMAP_OFFSET, &mmo); + * map = mmap(NULL, size, PROT_WRITE, MAP_SHARED, fd, mmo.offset); + * map[i] = 0xdeadbeaf; // issue barrier */ struct drm_xe_gem_mmap_offset { /** @extensions: Pointer to the first extension struct, if any */ From 380b0cdaa76bc8f5c16db16eaf48751e792ff041 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 10 Dec 2024 09:31:03 +0100 Subject: [PATCH 035/130] drm/xe: Move suballocator init to after display init No allocations should be done before we have had a chance to preserve the display fb. Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20241210083111.230484-4-dev@lankhorst.se Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/xe/xe_device.c | 6 ++++++ drivers/gpu/drm/xe/xe_tile.c | 12 ++++++++---- drivers/gpu/drm/xe/xe_tile.h | 1 + 3 files changed, 15 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 6ecbf7dd396cb..af9b2bb62dee5 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -840,6 +840,12 @@ int xe_device_probe(struct xe_device *xe) if (err) goto err; + for_each_tile(tile, xe, id) { + err = xe_tile_init(tile); + if (err) + goto err; + } + for_each_gt(gt, xe, id) { last_gt = id; diff --git a/drivers/gpu/drm/xe/xe_tile.c b/drivers/gpu/drm/xe/xe_tile.c index 07cf7cfe4abd5..2825553b568f7 100644 --- a/drivers/gpu/drm/xe/xe_tile.c +++ b/drivers/gpu/drm/xe/xe_tile.c @@ -170,10 +170,6 @@ int xe_tile_init_noalloc(struct xe_tile *tile) if (err) return err; - tile->mem.kernel_bb_pool = xe_sa_bo_manager_init(tile, SZ_1M, 16); - if (IS_ERR(tile->mem.kernel_bb_pool)) - return PTR_ERR(tile->mem.kernel_bb_pool); - xe_wa_apply_tile_workarounds(tile); err = xe_tile_sysfs_init(tile); @@ -181,6 +177,14 @@ int xe_tile_init_noalloc(struct xe_tile *tile) return 0; } +int xe_tile_init(struct xe_tile *tile) +{ + tile->mem.kernel_bb_pool = xe_sa_bo_manager_init(tile, SZ_1M, 16); + if (IS_ERR(tile->mem.kernel_bb_pool)) + return PTR_ERR(tile->mem.kernel_bb_pool); + + return 0; +} void xe_tile_migrate_wait(struct xe_tile *tile) { xe_migrate_wait(tile->migrate); diff --git a/drivers/gpu/drm/xe/xe_tile.h b/drivers/gpu/drm/xe/xe_tile.h index 1c9e42ade6b05..eb939316d55b0 100644 --- a/drivers/gpu/drm/xe/xe_tile.h +++ b/drivers/gpu/drm/xe/xe_tile.h @@ -12,6 +12,7 @@ struct xe_tile; int xe_tile_init_early(struct xe_tile *tile, struct xe_device *xe, u8 id); int xe_tile_init_noalloc(struct xe_tile *tile); +int xe_tile_init(struct xe_tile *tile); void xe_tile_migrate_wait(struct xe_tile *tile); From cfa9d40db8c30d894171010fe765d96e9bc6a47e Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Thu, 16 Jan 2025 19:21:55 -0800 Subject: [PATCH 036/130] drm/xe/oa: Preserve oa_ctrl unused bits UMD's have interest in setting unused bits of the oa_ctrl register "out of band" for certain experiments. To facilitate this, don't clobber previous oa_ctrl unused bits, i.e. rmw the values rather than simply write them. Fixes: e936f885f1e9 ("drm/xe/oa/uapi: Expose OA stream fd") Signed-off-by: Ashutosh Dixit Reviewed-by: Umesh Nerlige Ramappa Link: https://patchwork.freedesktop.org/patch/msgid/20250117032155.3048063-1-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/regs/xe_oa_regs.h | 6 ++++++ drivers/gpu/drm/xe/xe_oa.c | 12 ++++++++++-- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_oa_regs.h b/drivers/gpu/drm/xe/regs/xe_oa_regs.h index a49561e9f3c31..a79ad2da070c2 100644 --- a/drivers/gpu/drm/xe/regs/xe_oa_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_oa_regs.h @@ -51,6 +51,10 @@ /* Common to all OA units */ #define OA_OACONTROL_REPORT_BC_MASK REG_GENMASK(9, 9) #define OA_OACONTROL_COUNTER_SIZE_MASK REG_GENMASK(8, 8) +#define OAG_OACONTROL_USED_BITS \ + (OAG_OACONTROL_OA_PES_DISAG_EN | OAG_OACONTROL_OA_CCS_SELECT_MASK | \ + OAG_OACONTROL_OA_COUNTER_SEL_MASK | OAG_OACONTROL_OA_COUNTER_ENABLE | \ + OA_OACONTROL_REPORT_BC_MASK | OA_OACONTROL_COUNTER_SIZE_MASK) #define OAG_OA_DEBUG XE_REG(0xdaf8, XE_REG_OPTION_MASKED) #define OAG_OA_DEBUG_DISABLE_MMIO_TRG REG_BIT(14) @@ -78,6 +82,8 @@ #define OAM_CONTEXT_CONTROL_OFFSET (0x1bc) #define OAM_CONTROL_OFFSET (0x194) #define OAM_CONTROL_COUNTER_SEL_MASK REG_GENMASK(3, 1) +#define OAM_OACONTROL_USED_BITS \ + (OAM_CONTROL_COUNTER_SEL_MASK | OAG_OACONTROL_OA_COUNTER_ENABLE) #define OAM_DEBUG_OFFSET (0x198) #define OAM_STATUS_OFFSET (0x19c) #define OAM_MMIO_TRG_OFFSET (0x1d0) diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index eeb96b5f49e2a..6a08e6c92835f 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -452,6 +452,12 @@ static u32 __oa_ccs_select(struct xe_oa_stream *stream) return val; } +static u32 __oactrl_used_bits(struct xe_oa_stream *stream) +{ + return stream->hwe->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAG ? + OAG_OACONTROL_USED_BITS : OAM_OACONTROL_USED_BITS; +} + static void xe_oa_enable(struct xe_oa_stream *stream) { const struct xe_oa_format *format = stream->oa_buffer.format; @@ -472,14 +478,14 @@ static void xe_oa_enable(struct xe_oa_stream *stream) stream->hwe->oa_unit->type == DRM_XE_OA_UNIT_TYPE_OAG) val |= OAG_OACONTROL_OA_PES_DISAG_EN; - xe_mmio_write32(&stream->gt->mmio, regs->oa_ctrl, val); + xe_mmio_rmw32(&stream->gt->mmio, regs->oa_ctrl, __oactrl_used_bits(stream), val); } static void xe_oa_disable(struct xe_oa_stream *stream) { struct xe_mmio *mmio = &stream->gt->mmio; - xe_mmio_write32(mmio, __oa_regs(stream)->oa_ctrl, 0); + xe_mmio_rmw32(mmio, __oa_regs(stream)->oa_ctrl, __oactrl_used_bits(stream), 0); if (xe_mmio_wait32(mmio, __oa_regs(stream)->oa_ctrl, OAG_OACONTROL_OA_COUNTER_ENABLE, 0, 50000, NULL, false)) drm_err(&stream->oa->xe->drm, @@ -2534,6 +2540,8 @@ static void __xe_oa_init_oa_units(struct xe_gt *gt) u->type = DRM_XE_OA_UNIT_TYPE_OAM; } + xe_mmio_write32(>->mmio, u->regs.oa_ctrl, 0); + /* Ensure MMIO trigger remains disabled till there is a stream */ xe_mmio_write32(>->mmio, u->regs.oa_debug, oag_configure_mmio_trigger(NULL, false)); From 9ebb5846e1a3b1705f8a7cbc528888a1aa0b163e Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 21 Jan 2025 00:24:43 +0100 Subject: [PATCH 037/130] drm/xe/pf: Fix migration initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The migration support only needs to be initialized once, but it was incorrectly called from the xe_gt_sriov_pf_init_hw(), which is part of the reset flow and may be called multiple times. Fixes: d86e3737c7ab ("drm/xe/pf: Add functions to save and restore VF GuC state") Signed-off-by: Michal Wajdeczko Cc: Michał Winiarski Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250120232443.544-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt.c | 4 +++- drivers/gpu/drm/xe/xe_gt_sriov_pf.c | 14 +++++++++++++- drivers/gpu/drm/xe/xe_gt_sriov_pf.h | 6 ++++++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index b5c313a3e9460..01a4a852b8f43 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -532,8 +532,10 @@ static int all_fw_domain_init(struct xe_gt *gt) if (IS_SRIOV_PF(gt_to_xe(gt)) && !xe_gt_is_media_type(gt)) xe_lmtt_init_hw(>_to_tile(gt)->sriov.pf.lmtt); - if (IS_SRIOV_PF(gt_to_xe(gt))) + if (IS_SRIOV_PF(gt_to_xe(gt))) { + xe_gt_sriov_pf_init(gt); xe_gt_sriov_pf_init_hw(gt); + } xe_force_wake_put(gt_to_fw(gt), fw_ref); diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c index e71fc3d2bda22..6f906c8e8108b 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c @@ -68,6 +68,19 @@ int xe_gt_sriov_pf_init_early(struct xe_gt *gt) return 0; } +/** + * xe_gt_sriov_pf_init - Prepare SR-IOV PF data structures on PF. + * @gt: the &xe_gt to initialize + * + * Late one-time initialization of the PF data. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_gt_sriov_pf_init(struct xe_gt *gt) +{ + return xe_gt_sriov_pf_migration_init(gt); +} + static bool pf_needs_enable_ggtt_guest_update(struct xe_device *xe) { return GRAPHICS_VERx100(xe) == 1200; @@ -90,7 +103,6 @@ void xe_gt_sriov_pf_init_hw(struct xe_gt *gt) pf_enable_ggtt_guest_update(gt); xe_gt_sriov_pf_service_update(gt); - xe_gt_sriov_pf_migration_init(gt); } static u32 pf_get_vf_regs_stride(struct xe_device *xe) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf.h index 96fab779a906f..f474509411c0c 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf.h +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf.h @@ -10,6 +10,7 @@ struct xe_gt; #ifdef CONFIG_PCI_IOV int xe_gt_sriov_pf_init_early(struct xe_gt *gt); +int xe_gt_sriov_pf_init(struct xe_gt *gt); void xe_gt_sriov_pf_init_hw(struct xe_gt *gt); void xe_gt_sriov_pf_sanitize_hw(struct xe_gt *gt, unsigned int vfid); void xe_gt_sriov_pf_restart(struct xe_gt *gt); @@ -19,6 +20,11 @@ static inline int xe_gt_sriov_pf_init_early(struct xe_gt *gt) return 0; } +static inline int xe_gt_sriov_pf_init(struct xe_gt *gt) +{ + return 0; +} + static inline void xe_gt_sriov_pf_init_hw(struct xe_gt *gt) { } From 5994018ecffc9e70e192bede2270819d8c93b2d4 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 21 Jan 2025 10:48:32 +0100 Subject: [PATCH 038/130] drm/xe/guc: Fix sizeof(32) typo A small typo leads to the following static code checker warning: drivers/gpu/drm/xe/xe_guc_buf.c:81 xe_guc_buf_reserve() warn: sizeof(NUMBER)? Reported-by: Dan Carpenter Closes: https://lore.kernel.org/intel-xe/0d5bcbf1-79f9-4a10-a221-ddbaec9f6122@stanley.mountain/ Fixes: 696bfdf273ea ("drm/xe/guc: Introduce the GuC Buffer Cache") Signed-off-by: Michal Wajdeczko Cc: Dan Carpenter Cc: Matthew Brost Reviewed-by: Stuart Summers Link: https://patchwork.freedesktop.org/patch/msgid/20250121094832.588-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_guc_buf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc_buf.c b/drivers/gpu/drm/xe/xe_guc_buf.c index ce6d9830e13b6..0193c94dd6a00 100644 --- a/drivers/gpu/drm/xe/xe_guc_buf.c +++ b/drivers/gpu/drm/xe/xe_guc_buf.c @@ -78,7 +78,7 @@ struct xe_guc_buf xe_guc_buf_reserve(struct xe_guc_buf_cache *cache, u32 dwords) struct drm_suballoc *sa; if (cache->sam) - sa = __xe_sa_bo_new(cache->sam, dwords * sizeof(32), GFP_ATOMIC); + sa = __xe_sa_bo_new(cache->sam, dwords * sizeof(u32), GFP_ATOMIC); else sa = ERR_PTR(-EOPNOTSUPP); From e0a4cd6aceca0e9164d7304ac1a9b061e1d96529 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 17 Jan 2025 08:45:29 -0800 Subject: [PATCH 039/130] MAINTAINERS: Also exclude xe for drm-misc When the xe driver was added, it didn't extend the exclude entries for drm-misc, as done in commit 5a44d50f0072 ("MAINTAINERS: Update drm-misc entry to match all drivers"). Exclude it like is done for i915 and other drivers with dedicated maintainers. Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250117164529.393503-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- MAINTAINERS | 1 + 1 file changed, 1 insertion(+) diff --git a/MAINTAINERS b/MAINTAINERS index 17daa9ee93845..6664d39ab4c69 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7598,6 +7598,7 @@ X: drivers/gpu/drm/nouveau/ X: drivers/gpu/drm/radeon/ X: drivers/gpu/drm/renesas/rcar-du/ X: drivers/gpu/drm/tegra/ +X: drivers/gpu/drm/xe/ DRM DRIVERS FOR ALLWINNER A10 M: Maxime Ripard From dddc53806dd2a10e210d5ea08caec6d3f92440b2 Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Thu, 16 Jan 2025 10:46:59 -0800 Subject: [PATCH 040/130] drm/xe/ptl: Apply Wa_13011645652 Extend Wa_13011645652 to PTL. Signed-off-by: Vinay Belgaumkar Reviewed-by: Stuart Summers Signed-off-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20250116184659.384874-1-vinay.belgaumkar@intel.com --- drivers/gpu/drm/xe/xe_wa_oob.rules | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_wa_oob.rules b/drivers/gpu/drm/xe/xe_wa_oob.rules index 40438c3d9b723..228436532282c 100644 --- a/drivers/gpu/drm/xe/xe_wa_oob.rules +++ b/drivers/gpu/drm/xe/xe_wa_oob.rules @@ -28,6 +28,7 @@ 16022287689 GRAPHICS_VERSION(2001) GRAPHICS_VERSION(2004) 13011645652 GRAPHICS_VERSION(2004) + GRAPHICS_VERSION(3001) 14022293748 GRAPHICS_VERSION(2001) GRAPHICS_VERSION(2004) 22019794406 GRAPHICS_VERSION(2001) From d3fedff828bb7e4a422c42caeafd5d974e24ee43 Mon Sep 17 00:00:00 2001 From: Ashutosh Dixit Date: Wed, 15 Jan 2025 14:20:29 -0800 Subject: [PATCH 041/130] drm/xe/oa: Set stream->pollin in xe_oa_buffer_check_unlocked We rely on stream->pollin to decide whether or not to block during poll/read calls. However, currently there are blocking read code paths which don't even set stream->pollin. The best place to consistently set stream->pollin for all code paths is therefore to set it in xe_oa_buffer_check_unlocked. Fixes: e936f885f1e9 ("drm/xe/oa/uapi: Expose OA stream fd") Signed-off-by: Ashutosh Dixit Acked-by: Rodrigo Vivi Reviewed-by: Jonathan Cavitt Reviewed-by: Umesh Nerlige Ramappa Link: https://patchwork.freedesktop.org/patch/msgid/20250115222029.3002103-1-ashutosh.dixit@intel.com --- drivers/gpu/drm/xe/xe_oa.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 6a08e6c92835f..fa873f3d0a9d1 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -237,7 +237,6 @@ static bool xe_oa_buffer_check_unlocked(struct xe_oa_stream *stream) u32 tail, hw_tail, partial_report_size, available; int report_size = stream->oa_buffer.format->size; unsigned long flags; - bool pollin; spin_lock_irqsave(&stream->oa_buffer.ptr_lock, flags); @@ -282,11 +281,11 @@ static bool xe_oa_buffer_check_unlocked(struct xe_oa_stream *stream) stream->oa_buffer.tail = tail; available = xe_oa_circ_diff(stream, stream->oa_buffer.tail, stream->oa_buffer.head); - pollin = available >= stream->wait_num_reports * report_size; + stream->pollin = available >= stream->wait_num_reports * report_size; spin_unlock_irqrestore(&stream->oa_buffer.ptr_lock, flags); - return pollin; + return stream->pollin; } static enum hrtimer_restart xe_oa_poll_check_timer_cb(struct hrtimer *hrtimer) @@ -294,10 +293,8 @@ static enum hrtimer_restart xe_oa_poll_check_timer_cb(struct hrtimer *hrtimer) struct xe_oa_stream *stream = container_of(hrtimer, typeof(*stream), poll_check_timer); - if (xe_oa_buffer_check_unlocked(stream)) { - stream->pollin = true; + if (xe_oa_buffer_check_unlocked(stream)) wake_up(&stream->poll_wq); - } hrtimer_forward_now(hrtimer, ns_to_ktime(stream->poll_period_ns)); From 011c1e246a1d01c9d4b3b183e469bdb87b1f7bb8 Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Thu, 23 Jan 2025 21:04:06 -0800 Subject: [PATCH 042/130] drm/xe/pmu: Enable PMU interface Basic PMU enabling patch. Setup the basic framework for adding events. Based on previous versions by Bommu Krishnaiah, Aravind Iddamsetty and Riana Tauro, using i915 and rapl as reference implementations. Reviewed-by: Rodrigo Vivi Signed-off-by: Vinay Belgaumkar Link: https://patchwork.freedesktop.org/patch/msgid/20250124050411.2189060-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/Makefile | 2 + drivers/gpu/drm/xe/xe_device.c | 3 + drivers/gpu/drm/xe/xe_device_types.h | 4 + drivers/gpu/drm/xe/xe_pmu.c | 289 +++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_pmu.h | 18 ++ drivers/gpu/drm/xe/xe_pmu_types.h | 35 ++++ 6 files changed, 351 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_pmu.c create mode 100644 drivers/gpu/drm/xe/xe_pmu.h create mode 100644 drivers/gpu/drm/xe/xe_pmu_types.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 2e50a697f5494..9122e43187739 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -122,6 +122,8 @@ xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o # graphics hardware monitoring (HWMON) support xe-$(CONFIG_HWMON) += xe_hwmon.o +xe-$(CONFIG_PERF_EVENTS) += xe_pmu.o + # graphics virtualization (SR-IOV) support xe-y += \ xe_gt_sriov_vf.o \ diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index af9b2bb62dee5..90597a7ad0b09 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -49,6 +49,7 @@ #include "xe_pat.h" #include "xe_pcode.h" #include "xe_pm.h" +#include "xe_pmu.h" #include "xe_query.h" #include "xe_sriov.h" #include "xe_tile.h" @@ -872,6 +873,8 @@ int xe_device_probe(struct xe_device *xe) xe_oa_register(xe); + xe_pmu_register(&xe->pmu); + xe_debugfs_register(xe); xe_hwmon_register(xe); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 16ebb2859877f..58e79e19deaad 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -18,6 +18,7 @@ #include "xe_memirq_types.h" #include "xe_oa_types.h" #include "xe_platform_types.h" +#include "xe_pmu_types.h" #include "xe_pt_types.h" #include "xe_sriov_types.h" #include "xe_step_types.h" @@ -514,6 +515,9 @@ struct xe_device { int mode; } wedged; + /** @pmu: performance monitoring unit */ + struct xe_pmu pmu; + #ifdef TEST_VM_OPS_ERROR /** * @vm_inject_error_position: inject errors at different places in VM diff --git a/drivers/gpu/drm/xe/xe_pmu.c b/drivers/gpu/drm/xe/xe_pmu.c new file mode 100644 index 0000000000000..b3da3863928af --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pmu.c @@ -0,0 +1,289 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2025 Intel Corporation + */ + +#include +#include + +#include "xe_device.h" +#include "xe_pmu.h" + +/** + * DOC: Xe PMU (Performance Monitoring Unit) + * + * Expose events/counters like GT-C6 residency and GT frequency to user land via + * the perf interface. Events are per device. The GT can be selected with an + * extra config sub-field (bits 60-63). + * + * All events are listed in sysfs: + * + * $ ls -ld /sys/bus/event_source/devices/xe_* + * $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/events/ + * $ ls /sys/bus/event_source/devices/xe_0000_00_02.0/format/ + * + * The format directory has info regarding the configs that can be used. + * The standard perf tool can be used to grep for a certain event as well. + * Example: + * + * $ perf list | grep gt-c6 + * + * To sample a specific event for a GT at regular intervals: + * + * $ perf stat -e -I + */ + +#define XE_PMU_EVENT_GT_MASK GENMASK_ULL(63, 60) +#define XE_PMU_EVENT_ID_MASK GENMASK_ULL(11, 0) + +static unsigned int config_to_event_id(u64 config) +{ + return FIELD_GET(XE_PMU_EVENT_ID_MASK, config); +} + +static unsigned int config_to_gt_id(u64 config) +{ + return FIELD_GET(XE_PMU_EVENT_GT_MASK, config); +} + +static struct xe_gt *event_to_gt(struct perf_event *event) +{ + struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); + u64 gt = config_to_gt_id(event->attr.config); + + return xe_device_get_gt(xe, gt); +} + +static bool event_supported(struct xe_pmu *pmu, unsigned int gt, + unsigned int id) +{ + if (gt >= XE_MAX_GT_PER_TILE) + return false; + + return false; +} + +static void xe_pmu_event_destroy(struct perf_event *event) +{ + struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); + + drm_WARN_ON(&xe->drm, event->parent); + drm_dev_put(&xe->drm); +} + +static int xe_pmu_event_init(struct perf_event *event) +{ + struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); + struct xe_pmu *pmu = &xe->pmu; + unsigned int id, gt; + + if (!pmu->registered) + return -ENODEV; + + if (event->attr.type != event->pmu->type) + return -ENOENT; + + /* unsupported modes and filters */ + if (event->attr.sample_period) /* no sampling */ + return -EINVAL; + + if (event->cpu < 0) + return -EINVAL; + + gt = config_to_gt_id(event->attr.config); + id = config_to_event_id(event->attr.config); + if (!event_supported(pmu, gt, id)) + return -ENOENT; + + if (has_branch_stack(event)) + return -EOPNOTSUPP; + + if (!event->parent) { + drm_dev_get(&xe->drm); + event->destroy = xe_pmu_event_destroy; + } + + return 0; +} + +static u64 __xe_pmu_event_read(struct perf_event *event) +{ + struct xe_gt *gt = event_to_gt(event); + u64 val = 0; + + if (!gt) + return 0; + + return val; +} + +static void xe_pmu_event_read(struct perf_event *event) +{ + struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); + struct hw_perf_event *hwc = &event->hw; + struct xe_pmu *pmu = &xe->pmu; + u64 prev, new; + + if (!pmu->registered) { + event->hw.state = PERF_HES_STOPPED; + return; + } + + prev = local64_read(&hwc->prev_count); + do { + new = __xe_pmu_event_read(event); + } while (!local64_try_cmpxchg(&hwc->prev_count, &prev, new)); + + local64_add(new - prev, &event->count); +} + +static void xe_pmu_enable(struct perf_event *event) +{ + /* + * Store the current counter value so we can report the correct delta + * for all listeners. Even when the event was already enabled and has + * an existing non-zero value. + */ + local64_set(&event->hw.prev_count, __xe_pmu_event_read(event)); +} + +static void xe_pmu_event_start(struct perf_event *event, int flags) +{ + struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); + struct xe_pmu *pmu = &xe->pmu; + + if (!pmu->registered) + return; + + xe_pmu_enable(event); + event->hw.state = 0; +} + +static void xe_pmu_event_stop(struct perf_event *event, int flags) +{ + struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); + struct xe_pmu *pmu = &xe->pmu; + + if (pmu->registered) + if (flags & PERF_EF_UPDATE) + xe_pmu_event_read(event); + + event->hw.state = PERF_HES_STOPPED; +} + +static int xe_pmu_event_add(struct perf_event *event, int flags) +{ + struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); + struct xe_pmu *pmu = &xe->pmu; + + if (!pmu->registered) + return -ENODEV; + + if (flags & PERF_EF_START) + xe_pmu_event_start(event, flags); + + return 0; +} + +static void xe_pmu_event_del(struct perf_event *event, int flags) +{ + xe_pmu_event_stop(event, PERF_EF_UPDATE); +} + +PMU_FORMAT_ATTR(gt, "config:60-63"); +PMU_FORMAT_ATTR(event, "config:0-11"); + +static struct attribute *pmu_format_attrs[] = { + &format_attr_event.attr, + &format_attr_gt.attr, + NULL, +}; + +static const struct attribute_group pmu_format_attr_group = { + .name = "format", + .attrs = pmu_format_attrs, +}; + +static struct attribute *pmu_event_attrs[] = { + /* No events yet */ + NULL, +}; + +static const struct attribute_group pmu_events_attr_group = { + .name = "events", + .attrs = pmu_event_attrs, +}; + +/** + * xe_pmu_unregister() - Remove/cleanup PMU registration + * @arg: Ptr to pmu + */ +static void xe_pmu_unregister(void *arg) +{ + struct xe_pmu *pmu = arg; + struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); + + if (!pmu->registered) + return; + + pmu->registered = false; + + perf_pmu_unregister(&pmu->base); + kfree(pmu->name); +} + +/** + * xe_pmu_register() - Define basic PMU properties for Xe and add event callbacks. + * @pmu: the PMU object + * + * Returns 0 on success and an appropriate error code otherwise + */ +int xe_pmu_register(struct xe_pmu *pmu) +{ + struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); + static const struct attribute_group *attr_groups[] = { + &pmu_format_attr_group, + &pmu_events_attr_group, + NULL + }; + int ret = -ENOMEM; + char *name; + + if (IS_SRIOV_VF(xe)) + return 0; + + name = kasprintf(GFP_KERNEL, "xe_%s", + dev_name(xe->drm.dev)); + if (!name) + goto err; + + /* tools/perf reserves colons as special. */ + strreplace(name, ':', '_'); + + pmu->name = name; + pmu->base.attr_groups = attr_groups; + pmu->base.scope = PERF_PMU_SCOPE_SYS_WIDE; + pmu->base.module = THIS_MODULE; + pmu->base.task_ctx_nr = perf_invalid_context; + pmu->base.event_init = xe_pmu_event_init; + pmu->base.add = xe_pmu_event_add; + pmu->base.del = xe_pmu_event_del; + pmu->base.start = xe_pmu_event_start; + pmu->base.stop = xe_pmu_event_stop; + pmu->base.read = xe_pmu_event_read; + + ret = perf_pmu_register(&pmu->base, pmu->name, -1); + if (ret) + goto err_name; + + pmu->registered = true; + + return devm_add_action_or_reset(xe->drm.dev, xe_pmu_unregister, pmu); + +err_name: + kfree(name); +err: + drm_err(&xe->drm, "Failed to register PMU (ret=%d)!\n", ret); + + return ret; +} diff --git a/drivers/gpu/drm/xe/xe_pmu.h b/drivers/gpu/drm/xe/xe_pmu.h new file mode 100644 index 0000000000000..60c37126f87ec --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pmu.h @@ -0,0 +1,18 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ + +#ifndef _XE_PMU_H_ +#define _XE_PMU_H_ + +#include "xe_pmu_types.h" + +#if IS_ENABLED(CONFIG_PERF_EVENTS) +int xe_pmu_register(struct xe_pmu *pmu); +#else +static inline int xe_pmu_register(struct xe_pmu *pmu) { return 0; } +#endif + +#endif + diff --git a/drivers/gpu/drm/xe/xe_pmu_types.h b/drivers/gpu/drm/xe/xe_pmu_types.h new file mode 100644 index 0000000000000..0e8faae6bc1b3 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pmu_types.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ + +#ifndef _XE_PMU_TYPES_H_ +#define _XE_PMU_TYPES_H_ + +#include +#include + +#define XE_PMU_MAX_GT 2 + +/** + * struct xe_pmu - PMU related data per Xe device + * + * Stores per device PMU info that includes event/perf attributes and sampling + * counters across all GTs for this device. + */ +struct xe_pmu { + /** + * @base: PMU base. + */ + struct pmu base; + /** + * @registered: PMU is registered and not in the unregistering process. + */ + bool registered; + /** + * @name: Name as registered with perf core. + */ + const char *name; +}; + +#endif From 257a10c18e18cbcec7b9621820c11a5c9ec613bd Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 23 Jan 2025 21:04:07 -0800 Subject: [PATCH 043/130] drm/xe/pmu: Assert max gt XE_PMU_MAX_GT needs to be used due to a circular dependency, but we should make sure it doesn't go out of sync with XE_PMU_MAX_GT. Add a compile check for that. Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250124050411.2189060-2-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_pmu.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_pmu.c b/drivers/gpu/drm/xe/xe_pmu.c index b3da3863928af..df93ba96bdc1e 100644 --- a/drivers/gpu/drm/xe/xe_pmu.c +++ b/drivers/gpu/drm/xe/xe_pmu.c @@ -249,6 +249,8 @@ int xe_pmu_register(struct xe_pmu *pmu) int ret = -ENOMEM; char *name; + BUILD_BUG_ON(XE_MAX_GT_PER_TILE != XE_PMU_MAX_GT); + if (IS_SRIOV_VF(xe)) return 0; From ef7ce3938621e47c6aa2d517eab6f1d484ad365b Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 23 Jan 2025 21:04:08 -0800 Subject: [PATCH 044/130] drm/xe/pmu: Extract xe_pmu_event_update() Like other pmu drivers, keep the update separate from the read so it can be called from other methods (like stop()) without side effects. Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250124050411.2189060-3-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_pmu.c | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pmu.c b/drivers/gpu/drm/xe/xe_pmu.c index df93ba96bdc1e..33598272db6aa 100644 --- a/drivers/gpu/drm/xe/xe_pmu.c +++ b/drivers/gpu/drm/xe/xe_pmu.c @@ -117,18 +117,11 @@ static u64 __xe_pmu_event_read(struct perf_event *event) return val; } -static void xe_pmu_event_read(struct perf_event *event) +static void xe_pmu_event_update(struct perf_event *event) { - struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); struct hw_perf_event *hwc = &event->hw; - struct xe_pmu *pmu = &xe->pmu; u64 prev, new; - if (!pmu->registered) { - event->hw.state = PERF_HES_STOPPED; - return; - } - prev = local64_read(&hwc->prev_count); do { new = __xe_pmu_event_read(event); @@ -137,6 +130,19 @@ static void xe_pmu_event_read(struct perf_event *event) local64_add(new - prev, &event->count); } +static void xe_pmu_event_read(struct perf_event *event) +{ + struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); + struct xe_pmu *pmu = &xe->pmu; + + if (!pmu->registered) { + event->hw.state = PERF_HES_STOPPED; + return; + } + + xe_pmu_event_update(event); +} + static void xe_pmu_enable(struct perf_event *event) { /* @@ -166,7 +172,7 @@ static void xe_pmu_event_stop(struct perf_event *event, int flags) if (pmu->registered) if (flags & PERF_EF_UPDATE) - xe_pmu_event_read(event); + xe_pmu_event_update(event); event->hw.state = PERF_HES_STOPPED; } From 4ee64041bcca5289623c287336bfd94a42f42104 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 23 Jan 2025 21:04:09 -0800 Subject: [PATCH 045/130] drm/xe/pmu: Get/put runtime pm on event init When the event is created, make sure runtime pm is taken and later put: in order to read an event counter the GPU needs to remain accessible and doing a get/put during perf's read is not possible it's holding a raw_spinlock. Suggested-by: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250124050411.2189060-4-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_pmu.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_pmu.c b/drivers/gpu/drm/xe/xe_pmu.c index 33598272db6aa..6678340d6195b 100644 --- a/drivers/gpu/drm/xe/xe_pmu.c +++ b/drivers/gpu/drm/xe/xe_pmu.c @@ -7,6 +7,7 @@ #include #include "xe_device.h" +#include "xe_pm.h" #include "xe_pmu.h" /** @@ -68,6 +69,7 @@ static void xe_pmu_event_destroy(struct perf_event *event) struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); drm_WARN_ON(&xe->drm, event->parent); + xe_pm_runtime_put(xe); drm_dev_put(&xe->drm); } @@ -100,6 +102,7 @@ static int xe_pmu_event_init(struct perf_event *event) if (!event->parent) { drm_dev_get(&xe->drm); + xe_pm_runtime_get(xe); event->destroy = xe_pmu_event_destroy; } From 6ea5bf169ad4b5b2da1e7753031b446c22edecf3 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 23 Jan 2025 21:04:10 -0800 Subject: [PATCH 046/130] drm/xe/pmu: Add attribute skeleton Add the generic support for defining new attributes. This only adds the macros and common infra for the event counters, but no counters yet. This is going to be added as follow up changes. Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250124050411.2189060-5-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_pmu.c | 69 +++++++++++++++++++++++++++++-- drivers/gpu/drm/xe/xe_pmu_types.h | 4 ++ 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pmu.c b/drivers/gpu/drm/xe/xe_pmu.c index 6678340d6195b..6e19e08dd6176 100644 --- a/drivers/gpu/drm/xe/xe_pmu.c +++ b/drivers/gpu/drm/xe/xe_pmu.c @@ -61,7 +61,8 @@ static bool event_supported(struct xe_pmu *pmu, unsigned int gt, if (gt >= XE_MAX_GT_PER_TILE) return false; - return false; + return id < sizeof(pmu->supported_events) * BITS_PER_BYTE && + pmu->supported_events & BIT_ULL(id); } static void xe_pmu_event_destroy(struct perf_event *event) @@ -213,16 +214,73 @@ static const struct attribute_group pmu_format_attr_group = { .attrs = pmu_format_attrs, }; -static struct attribute *pmu_event_attrs[] = { - /* No events yet */ +__maybe_unused static ssize_t event_attr_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct perf_pmu_events_attr *pmu_attr = + container_of(attr, struct perf_pmu_events_attr, attr); + + return sprintf(buf, "event=%#04llx\n", pmu_attr->id); +} + +#define XE_EVENT_ATTR(name_, v_, id_) \ + PMU_EVENT_ATTR(name_, pmu_event_ ## v_, id_, event_attr_show) + +#define XE_EVENT_ATTR_UNIT(name_, v_, unit_) \ + PMU_EVENT_ATTR_STRING(name_.unit, pmu_event_unit_ ## v_, unit_) + +#define XE_EVENT_ATTR_GROUP(v_, id_, ...) \ + static struct attribute *pmu_attr_ ##v_[] = { \ + __VA_ARGS__, \ + NULL \ + }; \ + static umode_t is_visible_##v_(struct kobject *kobj, \ + struct attribute *attr, int idx) \ + { \ + struct perf_pmu_events_attr *pmu_attr; \ + struct xe_pmu *pmu; \ + \ + pmu_attr = container_of(attr, typeof(*pmu_attr), attr.attr); \ + pmu = container_of(dev_get_drvdata(kobj_to_dev(kobj)), \ + typeof(*pmu), base); \ + \ + return event_supported(pmu, 0, id_) ? attr->mode : 0; \ + } \ + static const struct attribute_group pmu_group_ ##v_ = { \ + .name = "events", \ + .attrs = pmu_attr_ ## v_, \ + .is_visible = is_visible_ ## v_, \ + } + +#define XE_EVENT_ATTR_SIMPLE(name_, v_, id_, unit_) \ + XE_EVENT_ATTR(name_, v_, id_) \ + XE_EVENT_ATTR_UNIT(name_, v_, unit_) \ + XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr, \ + &pmu_event_unit_ ##v_.attr.attr) + +#define XE_EVENT_ATTR_NOUNIT(name_, v_, id_) \ + XE_EVENT_ATTR(name_, v_, id_) \ + XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr) + +static struct attribute *pmu_empty_event_attrs[] = { + /* Empty - all events are added as groups with .attr_update() */ NULL, }; static const struct attribute_group pmu_events_attr_group = { .name = "events", - .attrs = pmu_event_attrs, + .attrs = pmu_empty_event_attrs, }; +static const struct attribute_group *pmu_events_attr_update[] = { + /* No events yet */ + NULL, +}; + +static void set_supported_events(struct xe_pmu *pmu) +{ +} + /** * xe_pmu_unregister() - Remove/cleanup PMU registration * @arg: Ptr to pmu @@ -273,6 +331,7 @@ int xe_pmu_register(struct xe_pmu *pmu) pmu->name = name; pmu->base.attr_groups = attr_groups; + pmu->base.attr_update = pmu_events_attr_update; pmu->base.scope = PERF_PMU_SCOPE_SYS_WIDE; pmu->base.module = THIS_MODULE; pmu->base.task_ctx_nr = perf_invalid_context; @@ -283,6 +342,8 @@ int xe_pmu_register(struct xe_pmu *pmu) pmu->base.stop = xe_pmu_event_stop; pmu->base.read = xe_pmu_event_read; + set_supported_events(pmu); + ret = perf_pmu_register(&pmu->base, pmu->name, -1); if (ret) goto err_name; diff --git a/drivers/gpu/drm/xe/xe_pmu_types.h b/drivers/gpu/drm/xe/xe_pmu_types.h index 0e8faae6bc1b3..f5ba4d56622cb 100644 --- a/drivers/gpu/drm/xe/xe_pmu_types.h +++ b/drivers/gpu/drm/xe/xe_pmu_types.h @@ -30,6 +30,10 @@ struct xe_pmu { * @name: Name as registered with perf core. */ const char *name; + /** + * @supported_events: Bitmap of supported events, indexed by event id + */ + u64 supported_events; }; #endif From 897286f2948cefe5f9d37fc3148fc19d0c7b160c Mon Sep 17 00:00:00 2001 From: Vinay Belgaumkar Date: Thu, 23 Jan 2025 21:04:11 -0800 Subject: [PATCH 047/130] drm/xe/pmu: Add GT C6 events Provide a PMU interface for GT C6 residency counters. The interface is similar to the one available for i915, but gt is passed in the config when creating the event. Sample usage and output: $ perf list | grep gt-c6 xe_0000_00_02.0/gt-c6-residency/ [Kernel PMU event] $ tail /sys/bus/event_source/devices/xe_0000_00_02.0/events/gt-c6-residency* ==> /sys/bus/event_source/devices/xe_0000_00_02.0/events/gt-c6-residency <== event=0x01 ==> /sys/bus/event_source/devices/xe_0000_00_02.0/events/gt-c6-residency.unit <== ms $ perf stat -e xe_0000_00_02.0/gt-c6-residency,gt=0/ -I1000 # time counts unit events 1.001196056 1,001 ms xe_0000_00_02.0/gt-c6-residency,gt=0/ 2.005216219 1,003 ms xe_0000_00_02.0/gt-c6-residency,gt=0/ Reviewed-by: Rodrigo Vivi Reviewed-by: Riana Tauro Signed-off-by: Vinay Belgaumkar Link: https://patchwork.freedesktop.org/patch/msgid/20250124050411.2189060-6-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_pmu.c | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pmu.c b/drivers/gpu/drm/xe/xe_pmu.c index 6e19e08dd6176..3910a82328ee3 100644 --- a/drivers/gpu/drm/xe/xe_pmu.c +++ b/drivers/gpu/drm/xe/xe_pmu.c @@ -7,6 +7,7 @@ #include #include "xe_device.h" +#include "xe_gt_idle.h" #include "xe_pm.h" #include "xe_pmu.h" @@ -47,6 +48,8 @@ static unsigned int config_to_gt_id(u64 config) return FIELD_GET(XE_PMU_EVENT_GT_MASK, config); } +#define XE_PMU_EVENT_GT_C6_RESIDENCY 0x01 + static struct xe_gt *event_to_gt(struct perf_event *event) { struct xe_device *xe = container_of(event->pmu, typeof(*xe), pmu.base); @@ -113,12 +116,16 @@ static int xe_pmu_event_init(struct perf_event *event) static u64 __xe_pmu_event_read(struct perf_event *event) { struct xe_gt *gt = event_to_gt(event); - u64 val = 0; if (!gt) return 0; - return val; + switch (config_to_event_id(event->attr.config)) { + case XE_PMU_EVENT_GT_C6_RESIDENCY: + return xe_gt_idle_residency_msec(>->gtidle); + } + + return 0; } static void xe_pmu_event_update(struct perf_event *event) @@ -214,8 +221,8 @@ static const struct attribute_group pmu_format_attr_group = { .attrs = pmu_format_attrs, }; -__maybe_unused static ssize_t event_attr_show(struct device *dev, - struct device_attribute *attr, char *buf) +static ssize_t event_attr_show(struct device *dev, + struct device_attribute *attr, char *buf) { struct perf_pmu_events_attr *pmu_attr = container_of(attr, struct perf_pmu_events_attr, attr); @@ -262,6 +269,8 @@ __maybe_unused static ssize_t event_attr_show(struct device *dev, XE_EVENT_ATTR(name_, v_, id_) \ XE_EVENT_ATTR_GROUP(v_, id_, &pmu_event_ ##v_.attr.attr) +XE_EVENT_ATTR_SIMPLE(gt-c6-residency, gt_c6_residency, XE_PMU_EVENT_GT_C6_RESIDENCY, "ms"); + static struct attribute *pmu_empty_event_attrs[] = { /* Empty - all events are added as groups with .attr_update() */ NULL, @@ -273,12 +282,16 @@ static const struct attribute_group pmu_events_attr_group = { }; static const struct attribute_group *pmu_events_attr_update[] = { - /* No events yet */ + &pmu_group_gt_c6_residency, NULL, }; static void set_supported_events(struct xe_pmu *pmu) { + struct xe_device *xe = container_of(pmu, typeof(*xe), pmu); + + if (!xe->info.skip_guc_pc) + pmu->supported_events |= BIT_ULL(XE_PMU_EVENT_GT_C6_RESIDENCY); } /** From 14b66746088098f43db1e8732ff8902ddbdd4de0 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 24 Jan 2025 19:52:47 +0100 Subject: [PATCH 048/130] drm/xe/pf: Use GuC Buffer Cache during policy provisioning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Start using GuC buffer cache for the SRIOV policy configuration actions. This is a required step before we could declare SRIOV PF as being a reclaim safe. Signed-off-by: Michal Wajdeczko Cc: Thomas Hellström Reviewed-by: Jonathan Cavitt Link: https://patchwork.freedesktop.org/patch/msgid/20250124185247.676-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c | 50 +++++++++++----------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c index c00fb354705f4..4445f660e6d10 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_policy.c @@ -10,6 +10,7 @@ #include "xe_gt_sriov_pf_helpers.h" #include "xe_gt_sriov_pf_policy.h" #include "xe_gt_sriov_printk.h" +#include "xe_guc_buf.h" #include "xe_guc_ct.h" #include "xe_guc_klv_helpers.h" #include "xe_pm.h" @@ -34,48 +35,28 @@ static int guc_action_update_vgt_policy(struct xe_guc *guc, u64 addr, u32 size) * Return: number of KLVs that were successfully parsed and saved, * negative error code on failure. */ -static int pf_send_policy_klvs(struct xe_gt *gt, const u32 *klvs, u32 num_dwords) +static int pf_send_policy_klvs(struct xe_gt *gt, struct xe_guc_buf buf, u32 num_dwords) { - const u32 bytes = num_dwords * sizeof(u32); - struct xe_tile *tile = gt_to_tile(gt); - struct xe_device *xe = tile_to_xe(tile); struct xe_guc *guc = >->uc.guc; - struct xe_bo *bo; - int ret; - - bo = xe_bo_create_pin_map(xe, tile, NULL, - ALIGN(bytes, PAGE_SIZE), - ttm_bo_type_kernel, - XE_BO_FLAG_VRAM_IF_DGFX(tile) | - XE_BO_FLAG_GGTT); - if (IS_ERR(bo)) - return PTR_ERR(bo); - - xe_map_memcpy_to(xe, &bo->vmap, 0, klvs, bytes); - ret = guc_action_update_vgt_policy(guc, xe_bo_ggtt_addr(bo), num_dwords); - - xe_bo_unpin_map_no_vm(bo); - - return ret; + return guc_action_update_vgt_policy(guc, xe_guc_buf_flush(buf), num_dwords); } /* * Return: 0 on success, -ENOKEY if some KLVs were not updated, -EPROTO if reply was malformed, * negative error code on failure. */ -static int pf_push_policy_klvs(struct xe_gt *gt, u32 num_klvs, - const u32 *klvs, u32 num_dwords) +static int pf_push_policy_buf_klvs(struct xe_gt *gt, u32 num_klvs, + struct xe_guc_buf buf, u32 num_dwords) { int ret; - xe_gt_assert(gt, num_klvs == xe_guc_klv_count(klvs, num_dwords)); - - ret = pf_send_policy_klvs(gt, klvs, num_dwords); + ret = pf_send_policy_klvs(gt, buf, num_dwords); if (ret != num_klvs) { int err = ret < 0 ? ret : ret < num_klvs ? -ENOKEY : -EPROTO; struct drm_printer p = xe_gt_info_printer(gt); + void *klvs = xe_guc_buf_cpu_ptr(buf); xe_gt_sriov_notice(gt, "Failed to push %u policy KLV%s (%pe)\n", num_klvs, str_plural(num_klvs), ERR_PTR(err)); @@ -86,6 +67,23 @@ static int pf_push_policy_klvs(struct xe_gt *gt, u32 num_klvs, return 0; } +/* + * Return: 0 on success, -ENOBUFS if there is no free buffer for the indirect data, + * negative error code on failure. + */ +static int pf_push_policy_klvs(struct xe_gt *gt, u32 num_klvs, + const u32 *klvs, u32 num_dwords) +{ + CLASS(xe_guc_buf_from_data, buf)(>->uc.guc.buf, klvs, num_dwords * sizeof(u32)); + + xe_gt_assert(gt, num_klvs == xe_guc_klv_count(klvs, num_dwords)); + + if (!xe_guc_buf_is_valid(buf)) + return -ENOBUFS; + + return pf_push_policy_buf_klvs(gt, num_klvs, buf, num_dwords); +} + static int pf_push_policy_u32(struct xe_gt *gt, u16 key, u32 value) { u32 klv[] = { From a4d1c5d0b99b75263a5626d2e52d569db3844b33 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Sat, 25 Jan 2025 22:55:05 +0100 Subject: [PATCH 049/130] drm/xe/pf: Move VFs reprovisioning to worker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since the GuC is reset during GT reset, we need to re-send the entire SR-IOV provisioning configuration to the GuC. But since this whole configuration is protected by the PF master mutex and we can't avoid making allocations under this mutex (like during LMEM provisioning), we can't do this reprovisioning from gt-reset path if we want to be reclaim-safe. Move VFs reprovisioning to a async worker that we will start from the gt-reset path. Signed-off-by: Michal Wajdeczko Cc: Thomas Hellström Cc: Matthew Brost Reviewed-by: Michał Winiarski Reviewed-by: Stuart Summers Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20250125215505.720-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt_sriov_pf.c | 43 +++++++++++++++++++++-- drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h | 10 ++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c index 6f906c8e8108b..d66478deab989 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c @@ -15,7 +15,11 @@ #include "xe_gt_sriov_pf_helpers.h" #include "xe_gt_sriov_pf_migration.h" #include "xe_gt_sriov_pf_service.h" +#include "xe_gt_sriov_printk.h" #include "xe_mmio.h" +#include "xe_pm.h" + +static void pf_worker_restart_func(struct work_struct *w); /* * VF's metadata is maintained in the flexible array where: @@ -41,6 +45,11 @@ static int pf_alloc_metadata(struct xe_gt *gt) return 0; } +static void pf_init_workers(struct xe_gt *gt) +{ + INIT_WORK(>->sriov.pf.workers.restart, pf_worker_restart_func); +} + /** * xe_gt_sriov_pf_init_early - Prepare SR-IOV PF data structures on PF. * @gt: the &xe_gt to initialize @@ -65,6 +74,8 @@ int xe_gt_sriov_pf_init_early(struct xe_gt *gt) if (err) return err; + pf_init_workers(gt); + return 0; } @@ -155,6 +166,35 @@ void xe_gt_sriov_pf_sanitize_hw(struct xe_gt *gt, unsigned int vfid) pf_clear_vf_scratch_regs(gt, vfid); } +static void pf_restart(struct xe_gt *gt) +{ + struct xe_device *xe = gt_to_xe(gt); + + xe_pm_runtime_get(xe); + xe_gt_sriov_pf_config_restart(gt); + xe_gt_sriov_pf_control_restart(gt); + xe_pm_runtime_put(xe); + + xe_gt_sriov_dbg(gt, "restart completed\n"); +} + +static void pf_worker_restart_func(struct work_struct *w) +{ + struct xe_gt *gt = container_of(w, typeof(*gt), sriov.pf.workers.restart); + + pf_restart(gt); +} + +static void pf_queue_restart(struct xe_gt *gt) +{ + struct xe_device *xe = gt_to_xe(gt); + + xe_gt_assert(gt, IS_SRIOV_PF(xe)); + + if (!queue_work(xe->sriov.wq, >->sriov.pf.workers.restart)) + xe_gt_sriov_dbg(gt, "restart already in queue!\n"); +} + /** * xe_gt_sriov_pf_restart - Restart SR-IOV support after a GT reset. * @gt: the &xe_gt @@ -163,6 +203,5 @@ void xe_gt_sriov_pf_sanitize_hw(struct xe_gt *gt, unsigned int vfid) */ void xe_gt_sriov_pf_restart(struct xe_gt *gt) { - xe_gt_sriov_pf_config_restart(gt); - xe_gt_sriov_pf_control_restart(gt); + pf_queue_restart(gt); } diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h index 0426b1a77069a..a64a6835ad656 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_types.h @@ -35,8 +35,17 @@ struct xe_gt_sriov_metadata { struct xe_gt_sriov_state_snapshot snapshot; }; +/** + * struct xe_gt_sriov_pf_workers - GT level workers used by the PF. + */ +struct xe_gt_sriov_pf_workers { + /** @restart: worker that executes actions post GT reset */ + struct work_struct restart; +}; + /** * struct xe_gt_sriov_pf - GT level PF virtualization data. + * @workers: workers data. * @service: service data. * @control: control data. * @policy: policy data. @@ -45,6 +54,7 @@ struct xe_gt_sriov_metadata { * @vfs: metadata for all VFs. */ struct xe_gt_sriov_pf { + struct xe_gt_sriov_pf_workers workers; struct xe_gt_sriov_pf_service service; struct xe_gt_sriov_pf_control control; struct xe_gt_sriov_pf_policy policy; From ef34861098c081a6222dbbe84439b571fa35c8a0 Mon Sep 17 00:00:00 2001 From: John Harrison Date: Fri, 17 Jan 2025 16:54:03 -0800 Subject: [PATCH 050/130] drm/xe: Upgrade complaint about missing slice info The steering code needs to know slice/subslice counts and this information should be retrieved from the hwconfig table. However, earlier platforms don't have it, hence the KMD has a fallback path. Newer platforms really should have the entries and if they are missing that is a bug that needs to be fixed in the table. So update the complaint to be an error on newer platforms and remove it completely for older ones that we know are bad (but are not POR for the Xe driver anyway). Also, re-word the message a little to make it clearer what the issue is. Signed-off-by: John Harrison Reviewed-by: Matt Roper Reviewed-by: Stuart Summers Acked-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250118005403.2960807-1-John.C.Harrison@Intel.com --- drivers/gpu/drm/xe/xe_gt_mcr.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_gt_mcr.c b/drivers/gpu/drm/xe/xe_gt_mcr.c index a1676b787fdcb..605aad3554e77 100644 --- a/drivers/gpu/drm/xe/xe_gt_mcr.c +++ b/drivers/gpu/drm/xe/xe_gt_mcr.c @@ -341,7 +341,13 @@ static unsigned int dss_per_group(struct xe_gt *gt) return DIV_ROUND_UP(max_subslices, max_slices); fallback: - xe_gt_dbg(gt, "GuC hwconfig cannot provide dss/slice; using typical fallback values\n"); + /* + * Some older platforms don't have tables or don't have complete tables. + * Newer platforms should always have the required info. + */ + if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 2000) + xe_gt_err(gt, "Slice/Subslice counts missing from hwconfig table; using typical fallback values\n"); + if (gt_to_xe(gt)->info.platform == XE_PVC) return 8; else if (GRAPHICS_VERx100(gt_to_xe(gt)) >= 1250) From a37934ea75d331fafa7fe80b6180642ba5193422 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Wed, 22 Jan 2025 21:11:11 -0800 Subject: [PATCH 051/130] drm/xe/devcoredump: Move exec queue snapshot to Contexts section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Having the exec queue snapshot inside a "GuC CT" section was always wrong. Commit c28fd6c358db ("drm/xe/devcoredump: Improve section headings and add tile info") tried to fix that bug, but with that also broke the mesa tool that parses the devcoredump, hence it was reverted in commit 70fb86a85dc9 ("drm/xe: Revert some changes that break a mesa debug tool"). With the mesa tool also fixed, this can propagate as a fix on both kernel and userspace side to avoid unnecessary headache for a debug feature. Cc: John Harrison Cc: Julia Filipchuk Cc: José Roberto de Souza Cc: stable@vger.kernel.org Fixes: 70fb86a85dc9 ("drm/xe: Revert some changes that break a mesa debug tool") Reviewed-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20250123051112.1938193-2-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_devcoredump.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_devcoredump.c b/drivers/gpu/drm/xe/xe_devcoredump.c index 81dc7795c0651..a7946a76777e7 100644 --- a/drivers/gpu/drm/xe/xe_devcoredump.c +++ b/drivers/gpu/drm/xe/xe_devcoredump.c @@ -119,11 +119,7 @@ static ssize_t __xe_devcoredump_read(char *buffer, size_t count, drm_puts(&p, "\n**** GuC CT ****\n"); xe_guc_ct_snapshot_print(ss->guc.ct, &p); - /* - * Don't add a new section header here because the mesa debug decoder - * tool expects the context information to be in the 'GuC CT' section. - */ - /* drm_puts(&p, "\n**** Contexts ****\n"); */ + drm_puts(&p, "\n**** Contexts ****\n"); xe_guc_exec_queue_snapshot_print(ss->ge, &p); drm_puts(&p, "\n**** Job ****\n"); From 2c95bbf5002776117a69caed3b31c10bf7341bec Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 23 Jan 2025 12:22:03 -0800 Subject: [PATCH 052/130] drm/xe: Fix and re-enable xe_print_blob_ascii85() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Commit 70fb86a85dc9 ("drm/xe: Revert some changes that break a mesa debug tool") partially reverted some changes to workaround breakage caused to mesa tools. However, in doing so it also broke fetching the GuC log via debugfs since xe_print_blob_ascii85() simply bails out. The fix is to avoid the extra newlines: the devcoredump interface is line-oriented and adding random newlines in the middle breaks it. If a tool is able to parse it by looking at the data and checking for chars that are out of the ascii85 space, it can still do so. A format change that breaks the line-oriented output on devcoredump however needs better coordination with existing tools. v2: Add suffix description comment v3: Reword explanation of xe_print_blob_ascii85() calling drm_puts() in a loop Reviewed-by: José Roberto de Souza Cc: John Harrison Cc: Julia Filipchuk Cc: José Roberto de Souza Cc: stable@vger.kernel.org Fixes: 70fb86a85dc9 ("drm/xe: Revert some changes that break a mesa debug tool") Fixes: ec1455ce7e35 ("drm/xe/devcoredump: Add ASCII85 dump helper function") Link: https://patchwork.freedesktop.org/patch/msgid/20250123202307.95103-2-jose.souza@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_devcoredump.c | 34 +++++++++++------------------ drivers/gpu/drm/xe/xe_devcoredump.h | 2 +- drivers/gpu/drm/xe/xe_guc_ct.c | 3 ++- drivers/gpu/drm/xe/xe_guc_log.c | 4 +++- 4 files changed, 19 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_devcoredump.c b/drivers/gpu/drm/xe/xe_devcoredump.c index a7946a76777e7..39fe485d20858 100644 --- a/drivers/gpu/drm/xe/xe_devcoredump.c +++ b/drivers/gpu/drm/xe/xe_devcoredump.c @@ -391,42 +391,34 @@ int xe_devcoredump_init(struct xe_device *xe) /** * xe_print_blob_ascii85 - print a BLOB to some useful location in ASCII85 * - * The output is split to multiple lines because some print targets, e.g. dmesg - * cannot handle arbitrarily long lines. Note also that printing to dmesg in - * piece-meal fashion is not possible, each separate call to drm_puts() has a - * line-feed automatically added! Therefore, the entire output line must be - * constructed in a local buffer first, then printed in one atomic output call. + * The output is split into multiple calls to drm_puts() because some print + * targets, e.g. dmesg, cannot handle arbitrarily long lines. These targets may + * add newlines, as is the case with dmesg: each drm_puts() call creates a + * separate line. * * There is also a scheduler yield call to prevent the 'task has been stuck for * 120s' kernel hang check feature from firing when printing to a slow target * such as dmesg over a serial port. * - * TODO: Add compression prior to the ASCII85 encoding to shrink huge buffers down. - * * @p: the printer object to output to * @prefix: optional prefix to add to output string + * @suffix: optional suffix to add at the end. 0 disables it and is + * not added to the output, which is useful when using multiple calls + * to dump data to @p * @blob: the Binary Large OBject to dump out * @offset: offset in bytes to skip from the front of the BLOB, must be a multiple of sizeof(u32) * @size: the size in bytes of the BLOB, must be a multiple of sizeof(u32) */ -void xe_print_blob_ascii85(struct drm_printer *p, const char *prefix, +void xe_print_blob_ascii85(struct drm_printer *p, const char *prefix, char suffix, const void *blob, size_t offset, size_t size) { const u32 *blob32 = (const u32 *)blob; char buff[ASCII85_BUFSZ], *line_buff; size_t line_pos = 0; - /* - * Splitting blobs across multiple lines is not compatible with the mesa - * debug decoder tool. Note that even dropping the explicit '\n' below - * doesn't help because the GuC log is so big some underlying implementation - * still splits the lines at 512K characters. So just bail completely for - * the moment. - */ - return; - #define DMESG_MAX_LINE_LEN 800 -#define MIN_SPACE (ASCII85_BUFSZ + 2) /* 85 + "\n\0" */ + /* Always leave space for the suffix char and the \0 */ +#define MIN_SPACE (ASCII85_BUFSZ + 2) /* 85 + "\0" */ if (size & 3) drm_printf(p, "Size not word aligned: %zu", size); @@ -458,7 +450,6 @@ void xe_print_blob_ascii85(struct drm_printer *p, const char *prefix, line_pos += strlen(line_buff + line_pos); if ((line_pos + MIN_SPACE) >= DMESG_MAX_LINE_LEN) { - line_buff[line_pos++] = '\n'; line_buff[line_pos++] = 0; drm_puts(p, line_buff); @@ -470,10 +461,11 @@ void xe_print_blob_ascii85(struct drm_printer *p, const char *prefix, } } + if (suffix) + line_buff[line_pos++] = suffix; + if (line_pos) { - line_buff[line_pos++] = '\n'; line_buff[line_pos++] = 0; - drm_puts(p, line_buff); } diff --git a/drivers/gpu/drm/xe/xe_devcoredump.h b/drivers/gpu/drm/xe/xe_devcoredump.h index 6a17e6d601022..5391a80a4d1ba 100644 --- a/drivers/gpu/drm/xe/xe_devcoredump.h +++ b/drivers/gpu/drm/xe/xe_devcoredump.h @@ -29,7 +29,7 @@ static inline int xe_devcoredump_init(struct xe_device *xe) } #endif -void xe_print_blob_ascii85(struct drm_printer *p, const char *prefix, +void xe_print_blob_ascii85(struct drm_printer *p, const char *prefix, char suffix, const void *blob, size_t offset, size_t size); #endif diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 8b65c5e959cc2..50c8076b51585 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -1724,7 +1724,8 @@ void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot, snapshot->g2h_outstanding); if (snapshot->ctb) - xe_print_blob_ascii85(p, "CTB data", snapshot->ctb, 0, snapshot->ctb_size); + xe_print_blob_ascii85(p, "CTB data", '\n', + snapshot->ctb, 0, snapshot->ctb_size); } else { drm_puts(p, "CT disabled\n"); } diff --git a/drivers/gpu/drm/xe/xe_guc_log.c b/drivers/gpu/drm/xe/xe_guc_log.c index 80151ff6a71f8..44482ea919924 100644 --- a/drivers/gpu/drm/xe/xe_guc_log.c +++ b/drivers/gpu/drm/xe/xe_guc_log.c @@ -207,8 +207,10 @@ void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_ remain = snapshot->size; for (i = 0; i < snapshot->num_chunks; i++) { size_t size = min(GUC_LOG_CHUNK_SIZE, remain); + const char *prefix = i ? NULL : "Log data"; + char suffix = i == snapshot->num_chunks - 1 ? '\n' : 0; - xe_print_blob_ascii85(p, i ? NULL : "Log data", snapshot->copy[i], 0, size); + xe_print_blob_ascii85(p, prefix, suffix, snapshot->copy[i], 0, size); remain -= size; } } From cb1f868ca13756c0c18ba54d1591332476760d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Roberto=20de=20Souza?= Date: Thu, 23 Jan 2025 12:22:04 -0800 Subject: [PATCH 053/130] drm/xe: Make GUC binaries dump consistent with other binaries in devcoredump MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit All other(hwsp, hwctx and vmas) binaries follow this format: [name].length: 0x1000 [name].data: xxxxxxx [name].error: errno The error one is just in case by some reason it was not able to capture the binary. So this GuC binaries should follow the same patern. v2: - renamed GUC binary to LOG Cc: John Harrison Cc: Lucas De Marchi Reviewed-by: Lucas De Marchi Signed-off-by: José Roberto de Souza Link: https://patchwork.freedesktop.org/patch/msgid/20250123202307.95103-3-jose.souza@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_guc_ct.c | 6 ++++-- drivers/gpu/drm/xe/xe_guc_log.c | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 50c8076b51585..497036675a38c 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -1723,9 +1723,11 @@ void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot, drm_printf(p, "\tg2h outstanding: %d\n", snapshot->g2h_outstanding); - if (snapshot->ctb) - xe_print_blob_ascii85(p, "CTB data", '\n', + if (snapshot->ctb) { + drm_printf(p, "[CTB].length: 0x%lx\n", snapshot->ctb_size); + xe_print_blob_ascii85(p, "[CTB].data", '\n', snapshot->ctb, 0, snapshot->ctb_size); + } } else { drm_puts(p, "CT disabled\n"); } diff --git a/drivers/gpu/drm/xe/xe_guc_log.c b/drivers/gpu/drm/xe/xe_guc_log.c index 44482ea919924..ab97ac728d7a8 100644 --- a/drivers/gpu/drm/xe/xe_guc_log.c +++ b/drivers/gpu/drm/xe/xe_guc_log.c @@ -204,10 +204,11 @@ void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_ drm_printf(p, "GuC timestamp: 0x%08llX [%llu]\n", snapshot->stamp, snapshot->stamp); drm_printf(p, "Log level: %u\n", snapshot->level); + drm_printf(p, "[LOG].length: 0x%lx\n", snapshot->size); remain = snapshot->size; for (i = 0; i < snapshot->num_chunks; i++) { size_t size = min(GUC_LOG_CHUNK_SIZE, remain); - const char *prefix = i ? NULL : "Log data"; + const char *prefix = i ? NULL : "[LOG].data"; char suffix = i == snapshot->num_chunks - 1 ? '\n' : 0; xe_print_blob_ascii85(p, prefix, suffix, snapshot->copy[i], 0, size); From 5e940312a2ac64ba0d6239aff72135226818b238 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Tue, 28 Jan 2025 15:26:30 +0530 Subject: [PATCH 054/130] drm/xe: Add functions and sysfs for boot survivability MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Boot Survivability is a software based workflow for recovering a system in a failed boot state. Here system recoverability is concerned with recovering the firmware responsible for boot. This is implemented by loading the driver with bare minimum (no drm card) to allow the firmware to be flashed through mei-gsc and collect telemetry. The driver's probe flow is modified such that it enters survivability mode when pcode initialization is incomplete and boot status denotes a failure. In this mode, drm card is not exposed and presence of survivability_mode entry in PCI sysfs is used to indicate survivability mode and provide additional information required for debug This patch adds initialization functions and exposes admin readable sysfs entries The new sysfs will have the below layout /sys/bus/.../bdf ├── survivability_mode v2: reorder headers fix doc remove survivability info and use mode to display information use separate function for logging survivability information for critical error (Rodrigo) v3: use for loop use dev logs instead of drm use helper function for aux history(Rodrigo) remove unnecessary error check of greater than max_scratch as we are reading only 3 bit v4: fix checkpatch warnings fix space (Rodrigo) rename register Signed-off-by: Riana Tauro Acked-by: Ashwin Kumar Kulkarni Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250128095632.1294722-2-riana.tauro@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_device_types.h | 4 + drivers/gpu/drm/xe/xe_pcode_api.h | 14 ++ drivers/gpu/drm/xe/xe_survivability_mode.c | 215 ++++++++++++++++++ drivers/gpu/drm/xe/xe_survivability_mode.h | 17 ++ .../gpu/drm/xe/xe_survivability_mode_types.h | 35 +++ 6 files changed, 286 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_survivability_mode.c create mode 100644 drivers/gpu/drm/xe/xe_survivability_mode.h create mode 100644 drivers/gpu/drm/xe/xe_survivability_mode_types.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 9122e43187739..ef900b9f04575 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -96,6 +96,7 @@ xe-y += xe_bb.o \ xe_sa.o \ xe_sched_job.o \ xe_step.o \ + xe_survivability_mode.o \ xe_sync.o \ xe_tile.o \ xe_tile_sysfs.o \ diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 58e79e19deaad..89f532b67bc43 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -22,6 +22,7 @@ #include "xe_pt_types.h" #include "xe_sriov_types.h" #include "xe_step_types.h" +#include "xe_survivability_mode_types.h" #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) #define TEST_VM_OPS_ERROR @@ -331,6 +332,9 @@ struct xe_device { u8 skip_pcode:1; } info; + /** @survivability: survivability information for device */ + struct xe_survivability survivability; + /** @irq: device interrupt state */ struct { /** @irq.lock: lock for processing irq's on this device */ diff --git a/drivers/gpu/drm/xe/xe_pcode_api.h b/drivers/gpu/drm/xe/xe_pcode_api.h index f153ce96f69a7..2bae9afdbd352 100644 --- a/drivers/gpu/drm/xe/xe_pcode_api.h +++ b/drivers/gpu/drm/xe/xe_pcode_api.h @@ -49,6 +49,20 @@ /* Domain IDs (param2) */ #define PCODE_MBOX_DOMAIN_HBM 0x2 +#define PCODE_SCRATCH(x) XE_REG(0x138320 + ((x) * 4)) +/* PCODE_SCRATCH0 */ +#define AUXINFO_REG_OFFSET REG_GENMASK(17, 15) +#define OVERFLOW_REG_OFFSET REG_GENMASK(14, 12) +#define HISTORY_TRACKING REG_BIT(11) +#define OVERFLOW_SUPPORT REG_BIT(10) +#define AUXINFO_SUPPORT REG_BIT(9) +#define BOOT_STATUS REG_GENMASK(3, 1) +#define CRITICAL_FAILURE 4 +#define NON_CRITICAL_FAILURE 7 + +/* Auxiliary info bits */ +#define AUXINFO_HISTORY_OFFSET REG_GENMASK(31, 29) + struct pcode_err_decode { int errno; const char *str; diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.c b/drivers/gpu/drm/xe/xe_survivability_mode.c new file mode 100644 index 0000000000000..9911e9f6b99b8 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_survivability_mode.c @@ -0,0 +1,215 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2025 Intel Corporation + */ + +#include "xe_survivability_mode.h" +#include "xe_survivability_mode_types.h" + +#include +#include +#include + +#include "xe_device.h" +#include "xe_gt.h" +#include "xe_mmio.h" +#include "xe_pcode_api.h" + +#define MAX_SCRATCH_MMIO 8 + +/** + * DOC: Xe Boot Survivability + * + * Boot Survivability is a software based workflow for recovering a system in a failed boot state + * Here system recoverability is concerned with recovering the firmware responsible for boot. + * + * This is implemented by loading the driver with bare minimum (no drm card) to allow the firmware + * to be flashed through mei and collect telemetry. The driver's probe flow is modified + * such that it enters survivability mode when pcode initialization is incomplete and boot status + * denotes a failure. The driver then populates the survivability_mode PCI sysfs indicating + * survivability mode and provides additional information required for debug + * + * KMD exposes below admin-only readable sysfs in survivability mode + * + * device/survivability_mode: The presence of this file indicates that the card is in survivability + * mode. Also, provides additional information on why the driver entered + * survivability mode. + * + * Capability Information - Provides boot status + * Postcode Information - Provides information about the failure + * Overflow Information - Provides history of previous failures + * Auxiliary Information - Certain failures may have information in + * addition to postcode information + */ + +static u32 aux_history_offset(u32 reg_value) +{ + return REG_FIELD_GET(AUXINFO_HISTORY_OFFSET, reg_value); +} + +static void set_survivability_info(struct xe_mmio *mmio, struct xe_survivability_info *info, + int id, char *name) +{ + strscpy(info[id].name, name, sizeof(info[id].name)); + info[id].reg = PCODE_SCRATCH(id).raw; + info[id].value = xe_mmio_read32(mmio, PCODE_SCRATCH(id)); +} + +static void populate_survivability_info(struct xe_device *xe) +{ + struct xe_survivability *survivability = &xe->survivability; + struct xe_survivability_info *info = survivability->info; + struct xe_mmio *mmio; + u32 id = 0, reg_value; + char name[NAME_MAX]; + int index; + + mmio = xe_root_tile_mmio(xe); + set_survivability_info(mmio, info, id, "Capability Info"); + reg_value = info[id].value; + + if (reg_value & HISTORY_TRACKING) { + id++; + set_survivability_info(mmio, info, id, "Postcode Info"); + + if (reg_value & OVERFLOW_SUPPORT) { + id = REG_FIELD_GET(OVERFLOW_REG_OFFSET, reg_value); + set_survivability_info(mmio, info, id, "Overflow Info"); + } + } + + if (reg_value & AUXINFO_SUPPORT) { + id = REG_FIELD_GET(AUXINFO_REG_OFFSET, reg_value); + + for (index = 0; id && reg_value; index++, reg_value = info[id].value, + id = aux_history_offset(reg_value)) { + snprintf(name, NAME_MAX, "Auxiliary Info %d", index); + set_survivability_info(mmio, info, id, name); + } + } +} + +static void log_survivability_info(struct pci_dev *pdev) +{ + struct xe_device *xe = pdev_to_xe_device(pdev); + struct xe_survivability *survivability = &xe->survivability; + struct xe_survivability_info *info = survivability->info; + int id; + + dev_info(&pdev->dev, "Survivability Boot Status : Critical Failure (%d)\n", + survivability->boot_status); + for (id = 0; id < MAX_SCRATCH_MMIO; id++) { + if (info[id].reg) + dev_info(&pdev->dev, "%s: 0x%x - 0x%x\n", info[id].name, + info[id].reg, info[id].value); + } +} + +static ssize_t survivability_mode_show(struct device *dev, + struct device_attribute *attr, char *buff) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct xe_device *xe = pdev_to_xe_device(pdev); + struct xe_survivability *survivability = &xe->survivability; + struct xe_survivability_info *info = survivability->info; + int index = 0, count = 0; + + for (index = 0; index < MAX_SCRATCH_MMIO; index++) { + if (info[index].reg) + count += sysfs_emit_at(buff, count, "%s: 0x%x - 0x%x\n", info[index].name, + info[index].reg, info[index].value); + } + + return count; +} + +static DEVICE_ATTR_ADMIN_RO(survivability_mode); + +static void enable_survivability_mode(struct pci_dev *pdev) +{ + struct device *dev = &pdev->dev; + struct xe_device *xe = pdev_to_xe_device(pdev); + struct xe_survivability *survivability = &xe->survivability; + int ret = 0; + + /* set survivability mode */ + survivability->mode = true; + dev_info(dev, "In Survivability Mode\n"); + + /* create survivability mode sysfs */ + ret = sysfs_create_file(&dev->kobj, &dev_attr_survivability_mode.attr); + if (ret) { + dev_warn(dev, "Failed to create survivability sysfs files\n"); + return; + } +} + +/** + * xe_survivability_mode_required - checks if survivability mode is required + * @xe: xe device instance + * + * This function reads the boot status from Pcode + * + * Return: true if boot status indicates failure, false otherwise + */ +bool xe_survivability_mode_required(struct xe_device *xe) +{ + struct xe_survivability *survivability = &xe->survivability; + struct xe_mmio *mmio = xe_root_tile_mmio(xe); + u32 data; + + data = xe_mmio_read32(mmio, PCODE_SCRATCH(0)); + survivability->boot_status = REG_FIELD_GET(BOOT_STATUS, data); + + return (survivability->boot_status == NON_CRITICAL_FAILURE || + survivability->boot_status == CRITICAL_FAILURE); +} + +/** + * xe_survivability_mode_remove - remove survivability mode + * @xe: xe device instance + * + * clean up sysfs entries of survivability mode + */ +void xe_survivability_mode_remove(struct xe_device *xe) +{ + struct xe_survivability *survivability = &xe->survivability; + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + struct device *dev = &pdev->dev; + + sysfs_remove_file(&dev->kobj, &dev_attr_survivability_mode.attr); + kfree(survivability->info); + pci_set_drvdata(pdev, NULL); +} + +/** + * xe_survivability_mode_init - Initialize the survivability mode + * @xe: xe device instance + * + * Initializes survivability information and enables survivability mode + */ +void xe_survivability_mode_init(struct xe_device *xe) +{ + struct xe_survivability *survivability = &xe->survivability; + struct xe_survivability_info *info; + struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + + survivability->size = MAX_SCRATCH_MMIO; + + info = kcalloc(survivability->size, sizeof(*info), GFP_KERNEL); + if (!info) + return; + + survivability->info = info; + + populate_survivability_info(xe); + + /* Only log debug information and exit if it is a critical failure */ + if (survivability->boot_status == CRITICAL_FAILURE) { + log_survivability_info(pdev); + kfree(survivability->info); + return; + } + + enable_survivability_mode(pdev); +} diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.h b/drivers/gpu/drm/xe/xe_survivability_mode.h new file mode 100644 index 0000000000000..410e3ee5f5d19 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_survivability_mode.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ + +#ifndef _XE_SURVIVABILITY_MODE_H_ +#define _XE_SURVIVABILITY_MODE_H_ + +#include + +struct xe_device; + +void xe_survivability_mode_init(struct xe_device *xe); +void xe_survivability_mode_remove(struct xe_device *xe); +bool xe_survivability_mode_required(struct xe_device *xe); + +#endif /* _XE_SURVIVABILITY_MODE_H_ */ diff --git a/drivers/gpu/drm/xe/xe_survivability_mode_types.h b/drivers/gpu/drm/xe/xe_survivability_mode_types.h new file mode 100644 index 0000000000000..19d433e253dfe --- /dev/null +++ b/drivers/gpu/drm/xe/xe_survivability_mode_types.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2025 Intel Corporation + */ + +#ifndef _XE_SURVIVABILITY_MODE_TYPES_H_ +#define _XE_SURVIVABILITY_MODE_TYPES_H_ + +#include +#include + +struct xe_survivability_info { + char name[NAME_MAX]; + u32 reg; + u32 value; +}; + +/** + * struct xe_survivability: Contains survivability mode information + */ +struct xe_survivability { + /** @info: struct that holds survivability info from scratch registers */ + struct xe_survivability_info *info; + + /** @size: number of scratch registers */ + u32 size; + + /** @boot_status: indicates critical/non critical boot failure */ + u8 boot_status; + + /** @mode: boolean to indicate survivability mode */ + bool mode; +}; + +#endif /* _XE_SURVIVABILITY_MODE_TYPES_H_ */ From 256daa32c9e0dcf924b3237e2165d8163f4d89cc Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Tue, 28 Jan 2025 15:26:31 +0530 Subject: [PATCH 055/130] drm/xe: Enable Boot Survivability mode Enable boot survivability mode if pcode initialization fails and if boot status indicates a failure. In this mode, drm card is not exposed and driver probe returns success after loading the bare minimum to allow firmware to be flashed via mei. v2: abstract survivability mode variable add BMG check inside function (Jani, Rodrigo) v3: return -EBUSY during system suspend (Anshuman) check survivability mode in pci probe only on error Signed-off-by: Riana Tauro Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250128095632.1294722-3-riana.tauro@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_device.c | 7 ++++++- drivers/gpu/drm/xe/xe_pci.c | 23 ++++++++++++++++++++-- drivers/gpu/drm/xe/xe_survivability_mode.c | 16 +++++++++++++++ drivers/gpu/drm/xe/xe_survivability_mode.h | 1 + 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 90597a7ad0b09..37ea1c099a672 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -52,6 +52,7 @@ #include "xe_pmu.h" #include "xe_query.h" #include "xe_sriov.h" +#include "xe_survivability_mode.h" #include "xe_tile.h" #include "xe_ttm_stolen_mgr.h" #include "xe_ttm_sys_mgr.h" @@ -694,8 +695,12 @@ int xe_device_probe_early(struct xe_device *xe) update_device_info(xe); err = xe_pcode_probe_early(xe); - if (err) + if (err) { + if (xe_survivability_mode_required(xe)) + xe_survivability_mode_init(xe); + return err; + } err = wait_for_lmem_ready(xe); if (err) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index bf35a18bf5e7e..f05cf26a088ce 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -30,6 +30,7 @@ #include "xe_pm.h" #include "xe_sriov.h" #include "xe_step.h" +#include "xe_survivability_mode.h" #include "xe_tile.h" enum toggle_d3cold { @@ -761,6 +762,9 @@ static void xe_pci_remove(struct pci_dev *pdev) if (IS_SRIOV_PF(xe)) xe_pci_sriov_configure(pdev, 0); + if (xe_survivability_mode_enabled(xe)) + return xe_survivability_mode_remove(xe); + xe_device_remove(xe); xe_pm_runtime_fini(xe); pci_set_drvdata(pdev, NULL); @@ -833,8 +837,19 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; err = xe_device_probe_early(xe); - if (err) + + /* + * In Boot Survivability mode, no drm card is exposed + * and driver is loaded with bare minimum to allow + * for firmware to be flashed through mei. Return + * success if survivability mode is enabled. + */ + if (err) { + if (xe_survivability_mode_enabled(xe)) + return 0; + return err; + } err = xe_info_init(xe, desc->graphics, desc->media); if (err) @@ -921,9 +936,13 @@ static void d3cold_toggle(struct pci_dev *pdev, enum toggle_d3cold toggle) static int xe_pci_suspend(struct device *dev) { struct pci_dev *pdev = to_pci_dev(dev); + struct xe_device *xe = pdev_to_xe_device(pdev); int err; - err = xe_pm_suspend(pdev_to_xe_device(pdev)); + if (xe_survivability_mode_enabled(xe)) + return -EBUSY; + + err = xe_pm_suspend(xe); if (err) return err; diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.c b/drivers/gpu/drm/xe/xe_survivability_mode.c index 9911e9f6b99b8..633f5effa3492 100644 --- a/drivers/gpu/drm/xe/xe_survivability_mode.c +++ b/drivers/gpu/drm/xe/xe_survivability_mode.c @@ -144,6 +144,19 @@ static void enable_survivability_mode(struct pci_dev *pdev) } } +/** + * xe_survivability_mode_enabled - check if survivability mode is enabled + * @xe: xe device instance + * + * Returns true if in survivability mode, false otherwise + */ +bool xe_survivability_mode_enabled(struct xe_device *xe) +{ + struct xe_survivability *survivability = &xe->survivability; + + return survivability->mode; +} + /** * xe_survivability_mode_required - checks if survivability mode is required * @xe: xe device instance @@ -158,6 +171,9 @@ bool xe_survivability_mode_required(struct xe_device *xe) struct xe_mmio *mmio = xe_root_tile_mmio(xe); u32 data; + if (!IS_DGFX(xe) || xe->info.platform < XE_BATTLEMAGE) + return false; + data = xe_mmio_read32(mmio, PCODE_SCRATCH(0)); survivability->boot_status = REG_FIELD_GET(BOOT_STATUS, data); diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.h b/drivers/gpu/drm/xe/xe_survivability_mode.h index 410e3ee5f5d19..f530507a22c62 100644 --- a/drivers/gpu/drm/xe/xe_survivability_mode.h +++ b/drivers/gpu/drm/xe/xe_survivability_mode.h @@ -12,6 +12,7 @@ struct xe_device; void xe_survivability_mode_init(struct xe_device *xe); void xe_survivability_mode_remove(struct xe_device *xe); +bool xe_survivability_mode_enabled(struct xe_device *xe); bool xe_survivability_mode_required(struct xe_device *xe); #endif /* _XE_SURVIVABILITY_MODE_H_ */ From 8b47c9cdb6a78364fe68f8af0abfd6f265577001 Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Tue, 28 Jan 2025 15:26:32 +0530 Subject: [PATCH 056/130] drm/xe: Initialize mei-gsc and vsec in survivability mode Initialize mei-gsc in survivability mode and disable HECI interrupts. Also initialize vsec in survivability mode Signed-off-by: Riana Tauro Reviewed-by: Rodrigo Vivi Reviewed-by: Alexander Usyskin Link: https://patchwork.freedesktop.org/patch/msgid/20250128095632.1294722-4-riana.tauro@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_heci_gsc.c | 3 ++- drivers/gpu/drm/xe/xe_survivability_mode.c | 7 +++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_heci_gsc.c b/drivers/gpu/drm/xe/xe_heci_gsc.c index d765bfd3636b4..06dc78d3a8123 100644 --- a/drivers/gpu/drm/xe/xe_heci_gsc.c +++ b/drivers/gpu/drm/xe/xe_heci_gsc.c @@ -12,6 +12,7 @@ #include "xe_drv.h" #include "xe_heci_gsc.h" #include "xe_platform_types.h" +#include "xe_survivability_mode.h" #define GSC_BAR_LENGTH 0x00000FFC @@ -200,7 +201,7 @@ void xe_heci_gsc_init(struct xe_device *xe) return; } - if (!def->use_polling) { + if (!def->use_polling && !xe_survivability_mode_enabled(xe)) { ret = heci_gsc_irq_setup(xe); if (ret) goto fail; diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.c b/drivers/gpu/drm/xe/xe_survivability_mode.c index 633f5effa3492..c619560af74f0 100644 --- a/drivers/gpu/drm/xe/xe_survivability_mode.c +++ b/drivers/gpu/drm/xe/xe_survivability_mode.c @@ -12,8 +12,10 @@ #include "xe_device.h" #include "xe_gt.h" +#include "xe_heci_gsc.h" #include "xe_mmio.h" #include "xe_pcode_api.h" +#include "xe_vsec.h" #define MAX_SCRATCH_MMIO 8 @@ -142,6 +144,10 @@ static void enable_survivability_mode(struct pci_dev *pdev) dev_warn(dev, "Failed to create survivability sysfs files\n"); return; } + + xe_heci_gsc_init(xe); + + xe_vsec_init(xe); } /** @@ -194,6 +200,7 @@ void xe_survivability_mode_remove(struct xe_device *xe) struct device *dev = &pdev->dev; sysfs_remove_file(&dev->kobj, &dev_attr_survivability_mode.attr); + xe_heci_gsc_fini(xe); kfree(survivability->info); pci_set_drvdata(pdev, NULL); } From fa8ffaae1b15236b8afb0fbbc04117ff7c900a83 Mon Sep 17 00:00:00 2001 From: Shekhar Chauhan Date: Tue, 28 Jan 2025 21:50:15 +0530 Subject: [PATCH 057/130] drm/xe/bmg: Add new PCI IDs Add 3 new PCI IDs for BMG. v2: Fix typo -> Replace '.' with ',' Signed-off-by: Shekhar Chauhan Reviewed-by: Clint Taylor Link: https://patchwork.freedesktop.org/patch/msgid/20250128162015.3288675-1-shekhar.chauhan@intel.com Signed-off-by: Rodrigo Vivi --- include/drm/intel/pciids.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/include/drm/intel/pciids.h b/include/drm/intel/pciids.h index 7883384acd5e8..e53d7d9bb64d9 100644 --- a/include/drm/intel/pciids.h +++ b/include/drm/intel/pciids.h @@ -817,7 +817,10 @@ MACRO__(0xE20B, ## __VA_ARGS__), \ MACRO__(0xE20C, ## __VA_ARGS__), \ MACRO__(0xE20D, ## __VA_ARGS__), \ - MACRO__(0xE212, ## __VA_ARGS__) + MACRO__(0xE210, ## __VA_ARGS__), \ + MACRO__(0xE212, ## __VA_ARGS__), \ + MACRO__(0xE215, ## __VA_ARGS__), \ + MACRO__(0xE216, ## __VA_ARGS__) /* PTL */ #define INTEL_PTL_IDS(MACRO__, ...) \ From 16016ade13f691da315fac7b23ebf1ab7b28b7ab Mon Sep 17 00:00:00 2001 From: Matt Atwood Date: Tue, 28 Jan 2025 09:51:02 -0800 Subject: [PATCH 058/130] drm/xe/ptl: Update the PTL pci id table Update to current bspec table. Bspec: 72574 Signed-off-by: Matt Atwood Reviewed-by: Clint Taylor Link: https://patchwork.freedesktop.org/patch/msgid/20250128175102.45797-1-matthew.s.atwood@intel.com Signed-off-by: Rodrigo Vivi --- include/drm/intel/pciids.h | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/include/drm/intel/pciids.h b/include/drm/intel/pciids.h index e53d7d9bb64d9..23f349f650afa 100644 --- a/include/drm/intel/pciids.h +++ b/include/drm/intel/pciids.h @@ -827,12 +827,10 @@ MACRO__(0xB080, ## __VA_ARGS__), \ MACRO__(0xB081, ## __VA_ARGS__), \ MACRO__(0xB082, ## __VA_ARGS__), \ + MACRO__(0xB083, ## __VA_ARGS__), \ + MACRO__(0xB08F, ## __VA_ARGS__), \ MACRO__(0xB090, ## __VA_ARGS__), \ - MACRO__(0xB091, ## __VA_ARGS__), \ - MACRO__(0xB092, ## __VA_ARGS__), \ MACRO__(0xB0A0, ## __VA_ARGS__), \ - MACRO__(0xB0A1, ## __VA_ARGS__), \ - MACRO__(0xB0A2, ## __VA_ARGS__), \ MACRO__(0xB0B0, ## __VA_ARGS__) #endif /* __PCIIDS_H__ */ From 55d4b69861e853ac987f6d593b44a3c18b468576 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Tue, 28 Jan 2025 17:32:48 -0500 Subject: [PATCH 059/130] Revert "drm/xe/lnl: Enable GuC SLPC DCC task" This reverts commit 50554bf3e56dd0c78ef1eedb685d0ab36c9c9987. DCC in LNL should be disabled. It was a mistake to decide to go against GuC platform defaults in this case and this could lead to regressions in some TDP limited scenarios instead of helping. Cc: Vinay Belgaumkar Cc: Jonathan Cavitt Reviewed-by: Jonathan Cavitt Link: https://patchwork.freedesktop.org/patch/msgid/20250128223248.660748-1-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_guc_pc.c | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c index 44b5211066efa..43f9617baba29 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.c +++ b/drivers/gpu/drm/xe/xe_guc_pc.c @@ -993,27 +993,6 @@ static int pc_init_freqs(struct xe_guc_pc *pc) return ret; } -static int slpc_enable_dcc(struct xe_guc_pc *pc) -{ - int ret; - - ret = pc_action_set_param(pc, SLPC_PARAM_TASK_ENABLE_DCC, 1); - if (ret) - return ret; - - return pc_action_set_param(pc, SLPC_PARAM_TASK_DISABLE_DCC, 0); -} - -static int slpc_set_policies(struct xe_guc_pc *pc) -{ - struct xe_device *xe = pc_to_xe(pc); - - if (xe->info.platform == XE_LUNARLAKE) - return slpc_enable_dcc(pc); - - return 0; -} - /** * xe_guc_pc_start - Start GuC's Power Conservation component * @pc: Xe_GuC_PC instance @@ -1058,10 +1037,6 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) goto out; } - ret = slpc_set_policies(pc); - if (ret) - goto out; - ret = pc_init_freqs(pc); if (ret) goto out; From 7748289df510638ba61fed86b59ce7d2fb4a194c Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Tue, 28 Jan 2025 07:42:42 -0800 Subject: [PATCH 060/130] drm/xe/guc: Fix size_t print format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use %zx format to print size_t to remove the following warning when building for i386: >> drivers/gpu/drm/xe/xe_guc_ct.c:1727:43: warning: format specifies type 'unsigned long' but the argument has type 'size_t' (aka 'unsigned int') [-Wformat] 1727 | drm_printf(p, "[CTB].length: 0x%lx\n", snapshot->ctb_size); | ~~~ ^~~~~~~~~~~~~~~~~~ | %zx Cc: José Roberto de Souza Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202501281627.H6nj184e-lkp@intel.com/ Fixes: cb1f868ca137 ("drm/xe: Make GUC binaries dump consistent with other binaries in devcoredump") Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250128154242.3371687-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_guc_ct.c | 2 +- drivers/gpu/drm/xe/xe_guc_log.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_ct.c b/drivers/gpu/drm/xe/xe_guc_ct.c index 497036675a38c..72ad576fc18eb 100644 --- a/drivers/gpu/drm/xe/xe_guc_ct.c +++ b/drivers/gpu/drm/xe/xe_guc_ct.c @@ -1724,7 +1724,7 @@ void xe_guc_ct_snapshot_print(struct xe_guc_ct_snapshot *snapshot, snapshot->g2h_outstanding); if (snapshot->ctb) { - drm_printf(p, "[CTB].length: 0x%lx\n", snapshot->ctb_size); + drm_printf(p, "[CTB].length: 0x%zx\n", snapshot->ctb_size); xe_print_blob_ascii85(p, "[CTB].data", '\n', snapshot->ctb, 0, snapshot->ctb_size); } diff --git a/drivers/gpu/drm/xe/xe_guc_log.c b/drivers/gpu/drm/xe/xe_guc_log.c index ab97ac728d7a8..80514a446ba28 100644 --- a/drivers/gpu/drm/xe/xe_guc_log.c +++ b/drivers/gpu/drm/xe/xe_guc_log.c @@ -204,7 +204,7 @@ void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_ drm_printf(p, "GuC timestamp: 0x%08llX [%llu]\n", snapshot->stamp, snapshot->stamp); drm_printf(p, "Log level: %u\n", snapshot->level); - drm_printf(p, "[LOG].length: 0x%lx\n", snapshot->size); + drm_printf(p, "[LOG].length: 0x%zx\n", snapshot->size); remain = snapshot->size; for (i = 0; i < snapshot->num_chunks; i++) { size_t size = min(GUC_LOG_CHUNK_SIZE, remain); From 8f6ddb4ab5db955bc826481d2f5c145aa5802ec1 Mon Sep 17 00:00:00 2001 From: Francois Dugast Date: Wed, 29 Jan 2025 18:52:41 +0100 Subject: [PATCH 061/130] drm/xe/gt_pagefault: Print engine class string The engine class index which is printed here is an internal representation for debugging. It is _not_ an index based on DRM_XE_ENGINE_CLASS_* values provided in the uAPI. Add the string representation of the engine class to the output in order to limit possible confusion by users when analyzing the logs. Reviewed-by: Matthew Brost Link: https://patchwork.freedesktop.org/patch/msgid/20250129175241.338043-1-francois.dugast@intel.com Signed-off-by: Francois Dugast --- drivers/gpu/drm/xe/xe_gt_pagefault.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index 79c426dc25059..39344aeab1120 100644 --- a/drivers/gpu/drm/xe/xe_gt_pagefault.c +++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c @@ -264,12 +264,13 @@ static void print_pagefault(struct xe_device *xe, struct pagefault *pf) "\tFaultType: %d\n" "\tAccessType: %d\n" "\tFaultLevel: %d\n" - "\tEngineClass: %d\n" + "\tEngineClass: %d %s\n" "\tEngineInstance: %d\n", pf->asid, pf->vfid, pf->pdata, upper_32_bits(pf->page_addr), lower_32_bits(pf->page_addr), pf->fault_type, pf->access_type, pf->fault_level, - pf->engine_class, pf->engine_instance); + pf->engine_class, xe_hw_engine_class_to_str(pf->engine_class), + pf->engine_instance); } #define PF_MSG_LEN_DW 4 From 21ccac0e22aaf27b767f9de4bf573e7c47f619c8 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Wed, 29 Jan 2025 20:59:46 +0100 Subject: [PATCH 062/130] drm/xe/pf: Don't send BEGIN_ID if VF has no context/doorbells MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit It turned out that GuC validates VF configuration immediately after receiving "some" set of configuration KLVs and complains if one of the critical, from GuC understanding, resource is left unprovisioned, even if PF should be still allowed to make late VF config adjustments, since VF was not yet started. This issue was discovered after we decided to asynchronously re-send configuration KLVs after GT reset/resume, as then fair VF auto-provisioning could already allocate some of the resources, which was a prerequiste for sending those config KLVs: # fair GGTT provisioning [] xe 0000:00:02.0: [drm] GT0: PF: pushed VF1 config with 2 KLVs: [] xe 0000:00:02.0: [drm] GT0: { key 0x0001 : 64b value 0x176a000 } # ggtt_start [] xe 0000:00:02.0: [drm] GT0: { key 0x0002 : 64b value 0xfd696000 } # ggtt_size [] xe 0000:00:02.0: [drm] GT0: PF: VF1 provisioned with 4251541504 (3.96 GiB) GGTT # re-provisioning worker [] xe 0000:00:02.0: [drm] *ERROR* GT0: H2G request 0x5503 failed: error 0x60 hint 0x0 [] xe 0000:00:02.0: [drm] GT0: PF: Failed to push VF1 14 config KLVs (-EIO) [] xe 0000:00:02.0: [drm] GT0: { key 0x0001 : 64b value 0x176a000 } # ggtt_start [] xe 0000:00:02.0: [drm] GT0: { key 0x0002 : 64b value 0xfd696000 } # ggtt_size [] xe 0000:00:02.0: [drm] GT0: { key 0x8a0b : 32b value 0 } # begin_ctx_id [] xe 0000:00:02.0: [drm] GT0: { key 0x0004 : 32b value 0 } # num_contexts [] xe 0000:00:02.0: [drm] GT0: { key 0x8a0a : 32b value 0 } # begin_db_id [] xe 0000:00:02.0: [drm] GT0: { key 0x0006 : 32b value 0 } # num_doorbells [] xe 0000:00:02.0: [drm] GT0: { key 0x8a01 : 32b value 0 } # exec_quantum [] xe 0000:00:02.0: [drm] GT0: { key 0x8a02 : 32b value 0 } # preempt_timeout [] xe 0000:00:02.0: [drm] GT0: { key 0x8a03 : 32b value 0 } # cat_error_count [] xe 0000:00:02.0: [drm] GT0: { key 0x8a04 : 32b value 0 } # engine_reset_count [] xe 0000:00:02.0: [drm] GT0: { key 0x8a05 : 32b value 0 } # page_fault_count [] xe 0000:00:02.0: [drm] GT0: { key 0x8a06 : 32b value 0 } # guc_time_us [] xe 0000:00:02.0: [drm] GT0: { key 0x8a07 : 32b value 0 } # irq_time_us [] xe 0000:00:02.0: [drm] GT0: { key 0x8a08 : 32b value 0 } # doorbell_time_us [] xe 0000:00:02.0: [drm] GT0: PF: Failed to push VF1 configuration (-EIO) To avoid such errors stop sending BEGIN_CONTEXT/DOORBELL_ID KLVs if no GuC context/doorbell IDs were provisioned to VF. Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/4176 Signed-off-by: Michal Wajdeczko Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20250129195947.764-2-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index 9db1c920219da..c219c55f23ab3 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -264,7 +264,7 @@ static u32 encode_config(u32 *cfg, const struct xe_gt_sriov_config *config, bool n += encode_config_ggtt(cfg, config, details); - if (details) { + if (details && config->num_ctxs) { cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_BEGIN_CONTEXT_ID); cfg[n++] = config->begin_ctx; } @@ -272,7 +272,7 @@ static u32 encode_config(u32 *cfg, const struct xe_gt_sriov_config *config, bool cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_NUM_CONTEXTS); cfg[n++] = config->num_ctxs; - if (details) { + if (details && config->num_dbs) { cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_BEGIN_DOORBELL_ID); cfg[n++] = config->begin_db; } From 33f17e2cbd930a2a00eb007d9b241b6db010a880 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Wed, 29 Jan 2025 20:59:47 +0100 Subject: [PATCH 063/130] drm/xe/pf: Reset GuC VF config when unprovisioning critical resource MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit GuC firmware counts received VF configuration KLVs and may start validation of the complete VF config even if some resources where unprovisioned in the meantime, leading to unexpected errors like: $ echo 1 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/contexts_quota $ echo 0 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/contexts_quota $ echo 1 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/doorbells_quota $ echo 0 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/doorbells_quota $ echo 1 | sudo tee /sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/ggtt_quota tee: '/sys/kernel/debug/dri/0000:00:02.0/gt0/vf1/ggtt_quota': Input/output error To mitigate this problem trigger explicit VF config reset after unprovisioning any of the critical resources (GGTT, context or doorbell IDs) that GuC is monitoring. Signed-off-by: Michal Wajdeczko Reviewed-by: Michał Winiarski Link: https://patchwork.freedesktop.org/patch/msgid/20250129195947.764-3-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 37 +++++++++++++++++++--- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index c219c55f23ab3..b1d994d655896 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -338,6 +338,26 @@ static int pf_push_full_vf_config(struct xe_gt *gt, unsigned int vfid) return err; } +static int pf_push_vf_cfg(struct xe_gt *gt, unsigned int vfid, bool reset) +{ + int err = 0; + + xe_gt_assert(gt, vfid); + lockdep_assert_held(xe_gt_sriov_pf_master_mutex(gt)); + + if (reset) + err = pf_send_vf_cfg_reset(gt, vfid); + if (!err) + err = pf_push_full_vf_config(gt, vfid); + + return err; +} + +static int pf_refresh_vf_cfg(struct xe_gt *gt, unsigned int vfid) +{ + return pf_push_vf_cfg(gt, vfid, true); +} + static u64 pf_get_ggtt_alignment(struct xe_gt *gt) { struct xe_device *xe = gt_to_xe(gt); @@ -434,6 +454,10 @@ static int pf_provision_vf_ggtt(struct xe_gt *gt, unsigned int vfid, u64 size) return err; pf_release_vf_config_ggtt(gt, config); + + err = pf_refresh_vf_cfg(gt, vfid); + if (unlikely(err)) + return err; } xe_gt_assert(gt, !xe_ggtt_node_allocated(config->ggtt_region)); @@ -759,6 +783,10 @@ static int pf_provision_vf_ctxs(struct xe_gt *gt, unsigned int vfid, u32 num_ctx return ret; pf_release_config_ctxs(gt, config); + + ret = pf_refresh_vf_cfg(gt, vfid); + if (unlikely(ret)) + return ret; } if (!num_ctxs) @@ -1056,6 +1084,10 @@ static int pf_provision_vf_dbs(struct xe_gt *gt, unsigned int vfid, u32 num_dbs) return ret; pf_release_config_dbs(gt, config); + + ret = pf_refresh_vf_cfg(gt, vfid); + if (unlikely(ret)) + return ret; } if (!num_dbs) @@ -2087,10 +2119,7 @@ int xe_gt_sriov_pf_config_push(struct xe_gt *gt, unsigned int vfid, bool refresh xe_gt_assert(gt, vfid); mutex_lock(xe_gt_sriov_pf_master_mutex(gt)); - if (refresh) - err = pf_send_vf_cfg_reset(gt, vfid); - if (!err) - err = pf_push_full_vf_config(gt, vfid); + err = pf_push_vf_cfg(gt, vfid, refresh); mutex_unlock(xe_gt_sriov_pf_master_mutex(gt)); if (unlikely(err)) { From c13a42f2107c768715fbac518072363b57258e36 Mon Sep 17 00:00:00 2001 From: Gustavo Sousa Date: Wed, 15 Jan 2025 11:08:04 -0300 Subject: [PATCH 064/130] drm/xe: Fix sort order of .o lists in Makefile The Makefile for xe asks us to keep the lists of object files sorted: # Please keep these build lists sorted! Reshuffle the lists into the correct sort order. That was done by filtering each unsorted list through 'LC_ALL=C sort'. Signed-off-by: Gustavo Sousa Reviewed-by: Lucas De Marchi Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250115140812.20799-1-gustavo.sousa@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/Makefile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index ef900b9f04575..fdd3a0c9cb377 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -34,8 +34,8 @@ xe-y += xe_bb.o \ xe_dma_buf.o \ xe_drm_client.o \ xe_exec.o \ - xe_execlist.o \ xe_exec_queue.o \ + xe_execlist.o \ xe_force_wake.o \ xe_ggtt.o \ xe_gpu_scheduler.o \ @@ -67,11 +67,11 @@ xe-y += xe_bb.o \ xe_guc_pc.o \ xe_guc_submit.o \ xe_heci_gsc.o \ + xe_huc.o \ xe_hw_engine.o \ xe_hw_engine_class_sysfs.o \ xe_hw_engine_group.o \ xe_hw_fence.o \ - xe_huc.o \ xe_irq.o \ xe_lrc.o \ xe_migrate.o \ @@ -91,8 +91,8 @@ xe-y += xe_bb.o \ xe_range_fence.o \ xe_reg_sr.o \ xe_reg_whitelist.o \ - xe_rtp.o \ xe_ring_ops.o \ + xe_rtp.o \ xe_sa.o \ xe_sched_job.o \ xe_step.o \ @@ -104,8 +104,8 @@ xe-y += xe_bb.o \ xe_trace_bo.o \ xe_trace_guc.o \ xe_trace_lrc.o \ - xe_ttm_sys_mgr.o \ xe_ttm_stolen_mgr.o \ + xe_ttm_sys_mgr.o \ xe_ttm_vram_mgr.o \ xe_tuning.o \ xe_uc.o \ @@ -114,8 +114,8 @@ xe-y += xe_bb.o \ xe_vram.o \ xe_vram_freq.o \ xe_vsec.o \ - xe_wait_user_fence.o \ xe_wa.o \ + xe_wait_user_fence.o \ xe_wopcm.o xe-$(CONFIG_HMM_MIRROR) += xe_hmm.o @@ -224,6 +224,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_display_wa.o \ i915-display/intel_dkl_phy.o \ i915-display/intel_dmc.o \ + i915-display/intel_dmc_wl.o \ i915-display/intel_dp.o \ i915-display/intel_dp_aux.o \ i915-display/intel_dp_aux_backlight.o \ @@ -271,7 +272,6 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ i915-display/intel_vdsc.o \ i915-display/intel_vga.o \ i915-display/intel_vrr.o \ - i915-display/intel_dmc_wl.o \ i915-display/intel_wm.o \ i915-display/skl_scaler.o \ i915-display/skl_universal_plane.o \ From b73aebc7a1e0fd9d2a9d8ab7b88ada58bd80bb9f Mon Sep 17 00:00:00 2001 From: Jakub Kolakowski Date: Tue, 28 Jan 2025 11:03:00 +0000 Subject: [PATCH 065/130] drm/xe/pf: Add runtime registers for graphics gen >= 30 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add missing runtime registers for graphics versions of 3000 or higher. This is required for Xe3 where additionally we have MIRROR_L3BANK_ENABLE register. Signed-off-by: Jakub Kolakowski Suggested-by: Piotr Piórkowski Cc: Adam Miszczak Cc: Jakub Kolakowski Cc: Lukasz Laguna Cc: Marcin Bernatowicz Cc: Michal Wajdeczko Cc: Piotr Piorkowski Cc: Satyanarayana K V P Reviewed-by: Satyanarayana K V P Tested-by: Marcin Bernatowicz Signed-off-by: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/20250128110300.2840596-2-jakub1.kolakowski@intel.com --- drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c | 23 ++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c index 924e75b94aec0..6b5f849a07223 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_service.c @@ -176,11 +176,32 @@ static const struct xe_reg ver_2000_runtime_regs[] = { TIMESTAMP_OVERRIDE, /* _MMIO(0x44074) */ }; +static const struct xe_reg ver_3000_runtime_regs[] = { + RPM_CONFIG0, /* _MMIO(0x0d00) */ + XEHP_FUSE4, /* _MMIO(0x9114) */ + MIRROR_FUSE3, /* _MMIO(0x9118) */ + MIRROR_FUSE1, /* _MMIO(0x911c) */ + MIRROR_L3BANK_ENABLE, /* _MMIO(0x9130) */ + XELP_EU_ENABLE, /* _MMIO(0x9134) */ + XELP_GT_GEOMETRY_DSS_ENABLE, /* _MMIO(0x913c) */ + GT_VEBOX_VDBOX_DISABLE, /* _MMIO(0x9140) */ + XEHP_GT_COMPUTE_DSS_ENABLE, /* _MMIO(0x9144) */ + XEHPC_GT_COMPUTE_DSS_ENABLE_EXT,/* _MMIO(0x9148) */ + XE2_GT_COMPUTE_DSS_2, /* _MMIO(0x914c) */ + XE2_GT_GEOMETRY_DSS_1, /* _MMIO(0x9150) */ + XE2_GT_GEOMETRY_DSS_2, /* _MMIO(0x9154) */ + CTC_MODE, /* _MMIO(0xa26c) */ + HUC_KERNEL_LOAD_INFO, /* _MMIO(0xc1dc) */ +}; + static const struct xe_reg *pick_runtime_regs(struct xe_device *xe, unsigned int *count) { const struct xe_reg *regs; - if (GRAPHICS_VERx100(xe) >= 2000) { + if (GRAPHICS_VERx100(xe) >= 3000) { + *count = ARRAY_SIZE(ver_3000_runtime_regs); + regs = ver_3000_runtime_regs; + } else if (GRAPHICS_VERx100(xe) >= 2000) { *count = ARRAY_SIZE(ver_2000_runtime_regs); regs = ver_2000_runtime_regs; } else if (GRAPHICS_VERx100(xe) >= 1270) { From cf29a866a139519d6274756d65ebc29c9d749034 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jan 2025 15:28:48 +0100 Subject: [PATCH 066/130] drm/xe/display: Add intel_plane_initial_vblank_wait We're changing the driver to have no interrupts during early init for Xe, so we poll the PIPE_FRMSTMSMP counter instead. Interrupts cannot be enabled during FB readout because memirq's requires an allocation. This would overwrite the FB we want to read out. While it might be possible to also run do the same in i915 and run it without interrupts, the platforms i915 supports had a less clear distinction between display and graphics. For this reason I choose only to touch Xe for now. Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250121142850.4960-1-dev@lankhorst.se Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/i915/display/intel_display.c | 6 +++--- .../drm/i915/display/intel_plane_initial.c | 7 ++++++- .../drm/i915/display/intel_plane_initial.h | 2 ++ drivers/gpu/drm/xe/display/xe_plane_initial.c | 19 ++++++++++++++++++- 4 files changed, 29 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display.c b/drivers/gpu/drm/i915/display/intel_display.c index 4271da219b410..6f6a535ea4864 100644 --- a/drivers/gpu/drm/i915/display/intel_display.c +++ b/drivers/gpu/drm/i915/display/intel_display.c @@ -796,7 +796,7 @@ void intel_plane_disable_noatomic(struct intel_crtc *crtc, if ((crtc_state->active_planes & ~BIT(PLANE_CURSOR)) == 0 && hsw_ips_disable(crtc_state)) { crtc_state->ips_enabled = false; - intel_crtc_wait_for_next_vblank(crtc); + intel_plane_initial_vblank_wait(crtc); } /* @@ -810,7 +810,7 @@ void intel_plane_disable_noatomic(struct intel_crtc *crtc, */ if (HAS_GMCH(dev_priv) && intel_set_memory_cxsr(dev_priv, false)) - intel_crtc_wait_for_next_vblank(crtc); + intel_plane_initial_vblank_wait(crtc); /* * Gen2 reports pipe underruns whenever all planes are disabled. @@ -820,7 +820,7 @@ void intel_plane_disable_noatomic(struct intel_crtc *crtc, intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false); intel_plane_disable_arm(NULL, plane, crtc_state); - intel_crtc_wait_for_next_vblank(crtc); + intel_plane_initial_vblank_wait(crtc); } unsigned int diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.c b/drivers/gpu/drm/i915/display/intel_plane_initial.c index 6789b7f140952..b1675b46e06cb 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.c +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.c @@ -14,6 +14,11 @@ #include "intel_frontbuffer.h" #include "intel_plane_initial.h" +void intel_plane_initial_vblank_wait(struct intel_crtc *crtc) +{ + intel_crtc_wait_for_next_vblank(crtc); +} + static bool intel_reuse_initial_plane_obj(struct intel_crtc *this, const struct intel_initial_plane_config plane_configs[], @@ -442,7 +447,7 @@ void intel_initial_plane_config(struct intel_display *display) intel_find_initial_plane_obj(crtc, plane_configs); if (display->funcs.display->fixup_initial_plane_config(crtc, plane_config)) - intel_crtc_wait_for_next_vblank(crtc); + intel_plane_initial_vblank_wait(crtc); plane_config_fini(plane_config); } diff --git a/drivers/gpu/drm/i915/display/intel_plane_initial.h b/drivers/gpu/drm/i915/display/intel_plane_initial.h index 6c6aa717ed21f..5c315acda2101 100644 --- a/drivers/gpu/drm/i915/display/intel_plane_initial.h +++ b/drivers/gpu/drm/i915/display/intel_plane_initial.h @@ -6,8 +6,10 @@ #ifndef __INTEL_PLANE_INITIAL_H__ #define __INTEL_PLANE_INITIAL_H__ +struct intel_crtc; struct intel_display; void intel_initial_plane_config(struct intel_display *display); +void intel_plane_initial_vblank_wait(struct intel_crtc *crtc); #endif diff --git a/drivers/gpu/drm/xe/display/xe_plane_initial.c b/drivers/gpu/drm/xe/display/xe_plane_initial.c index 2eb9633f163a7..a22e7adfb09d9 100644 --- a/drivers/gpu/drm/xe/display/xe_plane_initial.c +++ b/drivers/gpu/drm/xe/display/xe_plane_initial.c @@ -8,7 +8,9 @@ #include "regs/xe_gtt_defs.h" #include "xe_ggtt.h" +#include "xe_mmio.h" +#include "i915_reg.h" #include "intel_atomic_plane.h" #include "intel_crtc.h" #include "intel_display.h" @@ -22,6 +24,21 @@ #include +void intel_plane_initial_vblank_wait(struct intel_crtc *crtc) +{ + /* Early xe has no irq */ + struct xe_device *xe = to_xe_device(crtc->base.dev); + struct xe_reg pipe_frmtmstmp = XE_REG(i915_mmio_reg_offset(PIPE_FRMTMSTMP(crtc->pipe))); + u32 timestamp; + int ret; + + timestamp = xe_mmio_read32(xe_root_tile_mmio(xe), pipe_frmtmstmp); + + ret = xe_mmio_wait32_not(xe_root_tile_mmio(xe), pipe_frmtmstmp, ~0U, timestamp, 40000U, ×tamp, false); + if (ret < 0) + drm_warn(&xe->drm, "waiting for early vblank failed with %i\n", ret); +} + static bool intel_reuse_initial_plane_obj(struct intel_crtc *this, const struct intel_initial_plane_config plane_configs[], @@ -303,7 +320,7 @@ void intel_initial_plane_config(struct intel_display *display) intel_find_initial_plane_obj(crtc, plane_configs); if (display->funcs.display->fixup_initial_plane_config(crtc, plane_config)) - intel_crtc_wait_for_next_vblank(crtc); + intel_plane_initial_vblank_wait(crtc); plane_config_fini(plane_config); } From f595fe5f6ae7d74d7352e2577ca1577704b64b3b Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jan 2025 15:28:49 +0100 Subject: [PATCH 067/130] drm/xe: Defer irq init until after xe_display_init_noaccel As stated in previous commit, we have to move interrupt handling until after xe_display_init_noaccel, as using memirqs would require an allocation. A full solution will of course require memirq allocation to be moved, but the first part only focuses on the required changes to display. Reviewed-by: Ilia Levi Link: https://patchwork.freedesktop.org/patch/msgid/20250121142850.4960-2-dev@lankhorst.se Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/xe/xe_device.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 8fedc72e9db40..4d401e4da70b9 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -814,10 +814,6 @@ int xe_device_probe(struct xe_device *xe) if (err) return err; - err = xe_irq_install(xe); - if (err) - goto err; - err = probe_has_flat_ccs(xe); if (err) goto err; @@ -851,6 +847,10 @@ int xe_device_probe(struct xe_device *xe) goto err; } + err = xe_irq_install(xe); + if (err) + goto err; + for_each_gt(gt, xe, id) { last_gt = id; From 65e366ace5ee3637179658e8cf37f934c857f563 Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Tue, 21 Jan 2025 15:28:50 +0100 Subject: [PATCH 068/130] drm/xe/display: Use a single early init call for display Now that interrupts are disabled for xe_display_init_noaccel, both xe_display_init_noirq and xe_display_init_noaccel run in the same context. This means that we can get rid of the 3 different init calls. Without interrupts, nothing is touching display up to this point. Unify those 3 early display calls into a single xe_display_init_early(), this makes the init sequence cleaner, and display less tangled during init. Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250121142850.4960-3-dev@lankhorst.se Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/xe/display/xe_display.c | 73 +++++++------------------ drivers/gpu/drm/xe/display/xe_display.h | 8 +-- drivers/gpu/drm/xe/xe_device.c | 10 +--- 3 files changed, 22 insertions(+), 69 deletions(-) diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index b3921dbc52ff6..7f0d8f00acff7 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -101,19 +101,25 @@ int xe_display_create(struct xe_device *xe) return drmm_add_action_or_reset(&xe->drm, display_destroy, NULL); } -static void xe_display_fini_nommio(struct drm_device *dev, void *dummy) +static void xe_display_fini_early(void *arg) { - struct xe_device *xe = to_xe_device(dev); + struct xe_device *xe = arg; struct intel_display *display = &xe->display; if (!xe->info.probe_display) return; + intel_display_driver_remove_nogem(display); + intel_display_driver_remove_noirq(display); + intel_opregion_cleanup(display); intel_power_domains_cleanup(display); } -int xe_display_init_nommio(struct xe_device *xe) +int xe_display_init_early(struct xe_device *xe) { + struct intel_display *display = &xe->display; + int err; + if (!xe->info.probe_display) return 0; @@ -123,29 +129,6 @@ int xe_display_init_nommio(struct xe_device *xe) /* This must be called before any calls to HAS_PCH_* */ intel_detect_pch(xe); - return drmm_add_action_or_reset(&xe->drm, xe_display_fini_nommio, xe); -} - -static void xe_display_fini_noirq(void *arg) -{ - struct xe_device *xe = arg; - struct intel_display *display = &xe->display; - - if (!xe->info.probe_display) - return; - - intel_display_driver_remove_noirq(display); - intel_opregion_cleanup(display); -} - -int xe_display_init_noirq(struct xe_device *xe) -{ - struct intel_display *display = &xe->display; - int err; - - if (!xe->info.probe_display) - return 0; - intel_display_driver_early_probe(display); /* Early display init.. */ @@ -162,38 +145,20 @@ int xe_display_init_noirq(struct xe_device *xe) intel_display_device_info_runtime_init(display); err = intel_display_driver_probe_noirq(display); - if (err) { - intel_opregion_cleanup(display); - return err; - } - - return devm_add_action_or_reset(xe->drm.dev, xe_display_fini_noirq, xe); -} - -static void xe_display_fini_noaccel(void *arg) -{ - struct xe_device *xe = arg; - struct intel_display *display = &xe->display; - - if (!xe->info.probe_display) - return; - - intel_display_driver_remove_nogem(display); -} - -int xe_display_init_noaccel(struct xe_device *xe) -{ - struct intel_display *display = &xe->display; - int err; - - if (!xe->info.probe_display) - return 0; + if (err) + goto err_opregion; err = intel_display_driver_probe_nogem(display); if (err) - return err; + goto err_noirq; - return devm_add_action_or_reset(xe->drm.dev, xe_display_fini_noaccel, xe); + return devm_add_action_or_reset(xe->drm.dev, xe_display_fini_early, xe); +err_noirq: + intel_display_driver_remove_noirq(display); + intel_power_domains_cleanup(display); +err_opregion: + intel_opregion_cleanup(display); + return err; } int xe_display_init(struct xe_device *xe) diff --git a/drivers/gpu/drm/xe/display/xe_display.h b/drivers/gpu/drm/xe/display/xe_display.h index 233f81a26c255..e2a99624f7064 100644 --- a/drivers/gpu/drm/xe/display/xe_display.h +++ b/drivers/gpu/drm/xe/display/xe_display.h @@ -20,9 +20,7 @@ int xe_display_create(struct xe_device *xe); int xe_display_probe(struct xe_device *xe); -int xe_display_init_nommio(struct xe_device *xe); -int xe_display_init_noirq(struct xe_device *xe); -int xe_display_init_noaccel(struct xe_device *xe); +int xe_display_init_early(struct xe_device *xe); int xe_display_init(struct xe_device *xe); void xe_display_fini(struct xe_device *xe); @@ -54,9 +52,7 @@ static inline int xe_display_create(struct xe_device *xe) { return 0; } static inline int xe_display_probe(struct xe_device *xe) { return 0; } -static inline int xe_display_init_nommio(struct xe_device *xe) { return 0; } -static inline int xe_display_init_noirq(struct xe_device *xe) { return 0; } -static inline int xe_display_init_noaccel(struct xe_device *xe) { return 0; } +static inline int xe_display_init_early(struct xe_device *xe) { return 0; } static inline int xe_display_init(struct xe_device *xe) { return 0; } static inline void xe_display_fini(struct xe_device *xe) {} diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 4d401e4da70b9..8a2763e8a6e27 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -752,10 +752,6 @@ int xe_device_probe(struct xe_device *xe) return err; xe->info.mem_region_mask = 1; - err = xe_display_init_nommio(xe); - if (err) - return err; - err = xe_set_dma_info(xe); if (err) return err; @@ -810,10 +806,6 @@ int xe_device_probe(struct xe_device *xe) if (err) return err; - err = xe_display_init_noirq(xe); - if (err) - return err; - err = probe_has_flat_ccs(xe); if (err) goto err; @@ -837,7 +829,7 @@ int xe_device_probe(struct xe_device *xe) * This is the reason the first allocation needs to be done * inside display. */ - err = xe_display_init_noaccel(xe); + err = xe_display_init_early(xe); if (err) goto err; From d9bc304437da6b74ac2b6644fe47702b8286eb8d Mon Sep 17 00:00:00 2001 From: Riana Tauro Date: Fri, 31 Jan 2025 13:35:27 +0530 Subject: [PATCH 069/130] drm/xe: Skip survivability mode for VF Follow the probe flow in case of VF and do not enter survivability mode in case of pcode init failure. Fixes: 5e940312a2ac ("drm/xe: Add functions and sysfs for boot survivability") Suggested-by: Satyanarayana K V P Signed-off-by: Riana Tauro Reviewed-by: Satyanarayana K V P Link: https://patchwork.freedesktop.org/patch/msgid/20250131080527.2256475-1-riana.tauro@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_survivability_mode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_survivability_mode.c b/drivers/gpu/drm/xe/xe_survivability_mode.c index c619560af74f0..02b4eadf84079 100644 --- a/drivers/gpu/drm/xe/xe_survivability_mode.c +++ b/drivers/gpu/drm/xe/xe_survivability_mode.c @@ -177,7 +177,7 @@ bool xe_survivability_mode_required(struct xe_device *xe) struct xe_mmio *mmio = xe_root_tile_mmio(xe); u32 data; - if (!IS_DGFX(xe) || xe->info.platform < XE_BATTLEMAGE) + if (!IS_DGFX(xe) || xe->info.platform < XE_BATTLEMAGE || IS_SRIOV_VF(xe)) return false; data = xe_mmio_read32(mmio, PCODE_SCRATCH(0)); From ae5d9cde9b762fd4b7259e1f93a94e0c7f04681c Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 31 Jan 2025 14:39:08 -0800 Subject: [PATCH 070/130] drm/xe: Remove xe_dummy_exit() Since commit 014125c64d09 ("drm/xe: Support 'nomodeset' kernel command-line option") the dummy exit is not needed anymore since the caller check for a NULL pointer. Drop it. Reviewed-by: Raag Jadav Link: https://patchwork.freedesktop.org/patch/msgid/20250131223908.4147195-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_module.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_module.c b/drivers/gpu/drm/xe/xe_module.c index 07b27114be9af..7185a2cdf6e38 100644 --- a/drivers/gpu/drm/xe/xe_module.c +++ b/drivers/gpu/drm/xe/xe_module.c @@ -77,10 +77,6 @@ struct init_funcs { void (*exit)(void); }; -static void xe_dummy_exit(void) -{ -} - static const struct init_funcs init_funcs[] = { { .init = xe_check_nomodeset, @@ -103,7 +99,6 @@ static const struct init_funcs init_funcs[] = { }, { .init = xe_pm_module_init, - .exit = xe_dummy_exit, }, }; From ff48e05d8d1eefbdeb4504c0275c78654b858046 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:25 -0800 Subject: [PATCH 071/130] drm/xe/pxp: Initialize PXP structure and KCR reg As the first step towards adding PXP support, hook in the PXP init function, allocate the PXP structure and initialize the KCR register to allow PXP HWDRM sessions. v2: remove unneeded includes, free PXP memory on error (John) Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-2-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/Makefile | 1 + .../xe/compat-i915-headers/pxp/intel_pxp.h | 4 +- drivers/gpu/drm/xe/regs/xe_pxp_regs.h | 17 +++ drivers/gpu/drm/xe/xe_device.c | 6 + drivers/gpu/drm/xe/xe_device_types.h | 8 +- drivers/gpu/drm/xe/xe_pci.c | 2 + drivers/gpu/drm/xe/xe_pxp.c | 107 ++++++++++++++++++ drivers/gpu/drm/xe/xe_pxp.h | 13 +++ drivers/gpu/drm/xe/xe_pxp_types.h | 26 +++++ 9 files changed, 180 insertions(+), 4 deletions(-) create mode 100644 drivers/gpu/drm/xe/regs/xe_pxp_regs.h create mode 100644 drivers/gpu/drm/xe/xe_pxp.c create mode 100644 drivers/gpu/drm/xe/xe_pxp.h create mode 100644 drivers/gpu/drm/xe/xe_pxp_types.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index e6960db45b738..708e9f0108dc0 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -87,6 +87,7 @@ xe-y += xe_bb.o \ xe_preempt_fence.o \ xe_pt.o \ xe_pt_walk.o \ + xe_pxp.o \ xe_query.o \ xe_range_fence.o \ xe_reg_sr.o \ diff --git a/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h b/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h index 5dfc587c8237e..419e8e926f00f 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h @@ -10,9 +10,9 @@ #include struct drm_gem_object; -struct intel_pxp; +struct xe_pxp; -static inline int intel_pxp_key_check(struct intel_pxp *pxp, +static inline int intel_pxp_key_check(struct xe_pxp *pxp, struct drm_gem_object *obj, bool assign) { diff --git a/drivers/gpu/drm/xe/regs/xe_pxp_regs.h b/drivers/gpu/drm/xe/regs/xe_pxp_regs.h new file mode 100644 index 0000000000000..d67cf210d23d5 --- /dev/null +++ b/drivers/gpu/drm/xe/regs/xe_pxp_regs.h @@ -0,0 +1,17 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2024, Intel Corporation. All rights reserved. + */ + +#ifndef __XE_PXP_REGS_H__ +#define __XE_PXP_REGS_H__ + +#include "regs/xe_regs.h" + +/* The following registers are only valid on platforms with a media GT */ + +/* KCR enable/disable control */ +#define KCR_INIT XE_REG(0x3860f0) +#define KCR_INIT_ALLOW_DISPLAY_ME_WRITES REG_BIT(14) + +#endif /* __XE_PXP_REGS_H__ */ diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 8a2763e8a6e27..f30f8f668dee2 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -50,6 +50,7 @@ #include "xe_pcode.h" #include "xe_pm.h" #include "xe_pmu.h" +#include "xe_pxp.h" #include "xe_query.h" #include "xe_sriov.h" #include "xe_survivability_mode.h" @@ -861,6 +862,11 @@ int xe_device_probe(struct xe_device *xe) if (err) goto err_fini_oa; + /* A PXP init failure is not fatal */ + err = xe_pxp_init(xe); + if (err && err != -EOPNOTSUPP) + drm_err(&xe->drm, "PXP initialization failed: %pe\n", ERR_PTR(err)); + err = drm_dev_register(&xe->drm, 0); if (err) goto err_fini_display; diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 89f532b67bc43..c0e886bac1831 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -36,6 +36,7 @@ struct xe_ggtt; struct xe_pat_ops; +struct xe_pxp; #define XE_BO_INVALID_OFFSET LONG_MAX @@ -307,6 +308,8 @@ struct xe_device { u8 has_heci_gscfi:1; /** @info.has_llc: Device has a shared CPU+GPU last level cache */ u8 has_llc:1; + /** @info.has_pxp: Device has PXP support */ + u8 has_pxp:1; /** @info.has_range_tlb_invalidation: Has range based TLB invalidations */ u8 has_range_tlb_invalidation:1; /** @info.has_sriov: Supports SR-IOV */ @@ -508,6 +511,9 @@ struct xe_device { /** @oa: oa observation subsystem */ struct xe_oa oa; + /** @pxp: Encapsulate Protected Xe Path support */ + struct xe_pxp *pxp; + /** @needs_flr_on_fini: requests function-reset on fini */ bool needs_flr_on_fini; @@ -583,8 +589,6 @@ struct xe_device { unsigned int czclk_freq; unsigned int fsb_freq, mem_freq, is_ddr3; }; - - void *pxp; #endif }; diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index f05cf26a088ce..0a6e58d55682a 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -62,6 +62,7 @@ struct xe_device_desc { u8 has_heci_gscfi:1; u8 has_heci_cscfi:1; u8 has_llc:1; + u8 has_pxp:1; u8 has_sriov:1; u8 skip_guc_pc:1; u8 skip_mtcfg:1; @@ -618,6 +619,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.has_heci_gscfi = desc->has_heci_gscfi; xe->info.has_heci_cscfi = desc->has_heci_cscfi; xe->info.has_llc = desc->has_llc; + xe->info.has_pxp = desc->has_pxp; xe->info.has_sriov = desc->has_sriov; xe->info.skip_guc_pc = desc->skip_guc_pc; xe->info.skip_mtcfg = desc->skip_mtcfg; diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c new file mode 100644 index 0000000000000..1a4d12d37d964 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -0,0 +1,107 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2024 Intel Corporation. + */ + +#include "xe_pxp.h" + +#include + +#include "xe_device_types.h" +#include "xe_force_wake.h" +#include "xe_gt.h" +#include "xe_gt_types.h" +#include "xe_mmio.h" +#include "xe_pxp_types.h" +#include "xe_uc_fw.h" +#include "regs/xe_pxp_regs.h" + +/** + * DOC: PXP + * + * PXP (Protected Xe Path) allows execution and flip to display of protected + * (i.e. encrypted) objects. This feature is currently only supported in + * integrated parts. + */ + +static bool pxp_is_supported(const struct xe_device *xe) +{ + return xe->info.has_pxp && IS_ENABLED(CONFIG_INTEL_MEI_GSC_PROXY); +} + +static int kcr_pxp_set_status(const struct xe_pxp *pxp, bool enable) +{ + u32 val = enable ? _MASKED_BIT_ENABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES) : + _MASKED_BIT_DISABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES); + unsigned int fw_ref; + + fw_ref = xe_force_wake_get(gt_to_fw(pxp->gt), XE_FW_GT); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) + return -EIO; + + xe_mmio_write32(&pxp->gt->mmio, KCR_INIT, val); + xe_force_wake_put(gt_to_fw(pxp->gt), fw_ref); + + return 0; +} + +static int kcr_pxp_enable(const struct xe_pxp *pxp) +{ + return kcr_pxp_set_status(pxp, true); +} + +/** + * xe_pxp_init - initialize PXP support + * @xe: the xe_device structure + * + * Initialize the HW state and allocate the objects required for PXP support. + * Note that some of the requirement for PXP support (GSC proxy init, HuC auth) + * are performed asynchronously as part of the GSC init. PXP can only be used + * after both this function and the async worker have completed. + * + * Returns -EOPNOTSUPP if PXP is not supported, 0 if PXP initialization is + * successful, other errno value if there is an error during the init. + */ +int xe_pxp_init(struct xe_device *xe) +{ + struct xe_gt *gt = xe->tiles[0].media_gt; + struct xe_pxp *pxp; + int err; + + if (!pxp_is_supported(xe)) + return -EOPNOTSUPP; + + /* we only support PXP on single tile devices with a media GT */ + if (xe->info.tile_count > 1 || !gt) + return -EOPNOTSUPP; + + /* The GSCCS is required for submissions to the GSC FW */ + if (!(gt->info.engine_mask & BIT(XE_HW_ENGINE_GSCCS0))) + return -EOPNOTSUPP; + + /* PXP requires both GSC and HuC firmwares to be available */ + if (!xe_uc_fw_is_loadable(>->uc.gsc.fw) || + !xe_uc_fw_is_loadable(>->uc.huc.fw)) { + drm_info(&xe->drm, "skipping PXP init due to missing FW dependencies"); + return -EOPNOTSUPP; + } + + pxp = drmm_kzalloc(&xe->drm, sizeof(struct xe_pxp), GFP_KERNEL); + if (!pxp) + return -ENOMEM; + + pxp->xe = xe; + pxp->gt = gt; + + err = kcr_pxp_enable(pxp); + if (err) + goto out_free; + + xe->pxp = pxp; + + return 0; + +out_free: + drmm_kfree(&xe->drm, pxp); + return err; +} diff --git a/drivers/gpu/drm/xe/xe_pxp.h b/drivers/gpu/drm/xe/xe_pxp.h new file mode 100644 index 0000000000000..00f5e688c0d91 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pxp.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2024, Intel Corporation. All rights reserved. + */ + +#ifndef __XE_PXP_H__ +#define __XE_PXP_H__ + +struct xe_device; + +int xe_pxp_init(struct xe_device *xe); + +#endif /* __XE_PXP_H__ */ diff --git a/drivers/gpu/drm/xe/xe_pxp_types.h b/drivers/gpu/drm/xe/xe_pxp_types.h new file mode 100644 index 0000000000000..4639cf49d267b --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pxp_types.h @@ -0,0 +1,26 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2024, Intel Corporation. All rights reserved. + */ + +#ifndef __XE_PXP_TYPES_H__ +#define __XE_PXP_TYPES_H__ + +struct xe_device; +struct xe_gt; + +/** + * struct xe_pxp - pxp state + */ +struct xe_pxp { + /** @xe: Backpoiner to the xe_device struct */ + struct xe_device *xe; + + /** + * @gt: pointer to the gt that owns the submission-side of PXP + * (VDBOX, KCR and GSC) + */ + struct xe_gt *gt; +}; + +#endif /* __XE_PXP_TYPES_H__ */ From dcdd6b84d9acaa0794c29de7024cfdb20cfd7b92 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:26 -0800 Subject: [PATCH 072/130] drm/xe/pxp: Allocate PXP execution resources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PXP requires submissions to the HW for the following operations 1) Key invalidation, done via the VCS engine 2) Communication with the GSC FW for session management, done via the GSCCS. Key invalidation submissions are serialized (only 1 termination can be serviced at a given time) and done via GGTT, so we can allocate a simple BO and a kernel queue for it. Submissions for session management are tied to a PXP client (identified by a unique host_session_id); from the GSC POV this is a user-accessible construct, so all related submission must be done via PPGTT. The driver does not currently support PPGTT submission from within the kernel, so to add this support, the following changes have been included: - a new type of kernel-owned VM (marked as GSC), required to ensure we don't use fault mode on the engine and to mark the different lock usage with lockdep. - a new function to map a BO into a VM from within the kernel. v2: improve comments and function name, remove unneeded include (John) v3: fix variable/function names in documentation Signed-off-by: Daniele Ceraolo Spurio Cc: Matthew Brost Cc: Thomas Hellström Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-3-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h | 7 + drivers/gpu/drm/xe/xe_exec_queue.c | 3 + drivers/gpu/drm/xe/xe_pxp.c | 23 +- drivers/gpu/drm/xe/xe_pxp_submit.c | 199 ++++++++++++++++++ drivers/gpu/drm/xe/xe_pxp_submit.h | 14 ++ drivers/gpu/drm/xe/xe_pxp_types.h | 48 +++++ drivers/gpu/drm/xe/xe_vm.c | 119 ++++++++++- drivers/gpu/drm/xe/xe_vm.h | 6 + drivers/gpu/drm/xe/xe_vm_types.h | 1 + 10 files changed, 410 insertions(+), 11 deletions(-) create mode 100644 drivers/gpu/drm/xe/xe_pxp_submit.c create mode 100644 drivers/gpu/drm/xe/xe_pxp_submit.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 708e9f0108dc0..720d13c16fa54 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -88,6 +88,7 @@ xe-y += xe_bb.o \ xe_pt.o \ xe_pt_walk.o \ xe_pxp.o \ + xe_pxp_submit.o \ xe_query.o \ xe_range_fence.o \ xe_reg_sr.o \ diff --git a/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h b/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h index 57520809e48db..f3c4cf10ba208 100644 --- a/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h +++ b/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h @@ -6,6 +6,7 @@ #ifndef _ABI_GSC_PXP_COMMANDS_ABI_H #define _ABI_GSC_PXP_COMMANDS_ABI_H +#include #include /* Heci client ID for PXP commands */ @@ -13,6 +14,12 @@ #define PXP_APIVER(x, y) (((x) & 0xFFFF) << 16 | ((y) & 0xFFFF)) +/* + * A PXP sub-section in an HECI packet can be up to 64K big in each direction. + * This does not include the top-level GSC header. + */ +#define PXP_MAX_PACKET_SIZE SZ_64K + /* * there are a lot of status codes for PXP, but we only define the cross-API * common ones that we actually can handle in the kernel driver. Other failure diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 7e1abbbfba121..252bfa11cae92 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -153,6 +153,9 @@ struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *v struct xe_exec_queue *q; int err; + /* VMs for GSCCS queues (and only those) must have the XE_VM_FLAG_GSC flag */ + xe_assert(xe, !vm || (!!(vm->flags & XE_VM_FLAG_GSC) == !!(hwe->engine_id == XE_HW_ENGINE_GSCCS0))); + q = __xe_exec_queue_alloc(xe, vm, logical_mask, width, hwe, flags, extensions); if (IS_ERR(q)) diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 1a4d12d37d964..89d71a69cdff4 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -12,6 +12,7 @@ #include "xe_gt.h" #include "xe_gt_types.h" #include "xe_mmio.h" +#include "xe_pxp_submit.h" #include "xe_pxp_types.h" #include "xe_uc_fw.h" #include "regs/xe_pxp_regs.h" @@ -50,6 +51,20 @@ static int kcr_pxp_enable(const struct xe_pxp *pxp) return kcr_pxp_set_status(pxp, true); } +static int kcr_pxp_disable(const struct xe_pxp *pxp) +{ + return kcr_pxp_set_status(pxp, false); +} + +static void pxp_fini(void *arg) +{ + struct xe_pxp *pxp = arg; + + xe_pxp_destroy_execution_resources(pxp); + + /* no need to explicitly disable KCR since we're going to do an FLR */ +} + /** * xe_pxp_init - initialize PXP support * @xe: the xe_device structure @@ -97,10 +112,16 @@ int xe_pxp_init(struct xe_device *xe) if (err) goto out_free; + err = xe_pxp_allocate_execution_resources(pxp); + if (err) + goto out_kcr_disable; + xe->pxp = pxp; - return 0; + return devm_add_action_or_reset(xe->drm.dev, pxp_fini, pxp); +out_kcr_disable: + kcr_pxp_disable(pxp); out_free: drmm_kfree(&xe->drm, pxp); return err; diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.c b/drivers/gpu/drm/xe/xe_pxp_submit.c new file mode 100644 index 0000000000000..52a6143b5ebe8 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pxp_submit.c @@ -0,0 +1,199 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright(c) 2024 Intel Corporation. + */ + +#include "xe_pxp_submit.h" + +#include + +#include "xe_device_types.h" +#include "xe_bo.h" +#include "xe_exec_queue.h" +#include "xe_gsc_submit.h" +#include "xe_gt.h" +#include "xe_pxp_types.h" +#include "xe_vm.h" + +/* + * The VCS is used for kernel-owned GGTT submissions to issue key termination. + * Terminations are serialized, so we only need a single queue and a single + * batch. + */ +static int allocate_vcs_execution_resources(struct xe_pxp *pxp) +{ + struct xe_gt *gt = pxp->gt; + struct xe_device *xe = pxp->xe; + struct xe_tile *tile = gt_to_tile(gt); + struct xe_hw_engine *hwe; + struct xe_exec_queue *q; + struct xe_bo *bo; + int err; + + hwe = xe_gt_hw_engine(gt, XE_ENGINE_CLASS_VIDEO_DECODE, 0, true); + if (!hwe) + return -ENODEV; + + q = xe_exec_queue_create(xe, NULL, BIT(hwe->logical_instance), 1, hwe, + EXEC_QUEUE_FLAG_KERNEL | EXEC_QUEUE_FLAG_PERMANENT, 0); + if (IS_ERR(q)) + return PTR_ERR(q); + + /* + * Each termination is 16 DWORDS, so 4K is enough to contain a + * termination for each sessions. + */ + bo = xe_bo_create_pin_map(xe, tile, 0, SZ_4K, ttm_bo_type_kernel, + XE_BO_FLAG_SYSTEM | XE_BO_FLAG_PINNED | XE_BO_FLAG_GGTT); + if (IS_ERR(bo)) { + err = PTR_ERR(bo); + goto out_queue; + } + + pxp->vcs_exec.q = q; + pxp->vcs_exec.bo = bo; + + return 0; + +out_queue: + xe_exec_queue_put(q); + return err; +} + +static void destroy_vcs_execution_resources(struct xe_pxp *pxp) +{ + if (pxp->vcs_exec.bo) + xe_bo_unpin_map_no_vm(pxp->vcs_exec.bo); + + if (pxp->vcs_exec.q) + xe_exec_queue_put(pxp->vcs_exec.q); +} + +#define PXP_BB_SIZE XE_PAGE_SIZE +static int allocate_gsc_client_resources(struct xe_gt *gt, + struct xe_pxp_gsc_client_resources *gsc_res, + size_t inout_size) +{ + struct xe_tile *tile = gt_to_tile(gt); + struct xe_device *xe = tile_to_xe(tile); + struct xe_hw_engine *hwe; + struct xe_vm *vm; + struct xe_bo *bo; + struct xe_exec_queue *q; + struct dma_fence *fence; + long timeout; + int err = 0; + + hwe = xe_gt_hw_engine(gt, XE_ENGINE_CLASS_OTHER, 0, true); + + /* we shouldn't reach here if the GSC engine is not available */ + xe_assert(xe, hwe); + + /* PXP instructions must be issued from PPGTT */ + vm = xe_vm_create(xe, XE_VM_FLAG_GSC); + if (IS_ERR(vm)) + return PTR_ERR(vm); + + /* We allocate a single object for the batch and the in/out memory */ + xe_vm_lock(vm, false); + bo = xe_bo_create_pin_map(xe, tile, vm, PXP_BB_SIZE + inout_size * 2, + ttm_bo_type_kernel, + XE_BO_FLAG_SYSTEM | XE_BO_FLAG_PINNED | XE_BO_FLAG_NEEDS_UC); + xe_vm_unlock(vm); + if (IS_ERR(bo)) { + err = PTR_ERR(bo); + goto vm_out; + } + + fence = xe_vm_bind_kernel_bo(vm, bo, NULL, 0, XE_CACHE_WB); + if (IS_ERR(fence)) { + err = PTR_ERR(fence); + goto bo_out; + } + + timeout = dma_fence_wait_timeout(fence, false, HZ); + dma_fence_put(fence); + if (timeout <= 0) { + err = timeout ?: -ETIME; + goto bo_out; + } + + q = xe_exec_queue_create(xe, vm, BIT(hwe->logical_instance), 1, hwe, + EXEC_QUEUE_FLAG_KERNEL | + EXEC_QUEUE_FLAG_PERMANENT, 0); + if (IS_ERR(q)) { + err = PTR_ERR(q); + goto bo_out; + } + + gsc_res->vm = vm; + gsc_res->bo = bo; + gsc_res->inout_size = inout_size; + gsc_res->batch = IOSYS_MAP_INIT_OFFSET(&bo->vmap, 0); + gsc_res->msg_in = IOSYS_MAP_INIT_OFFSET(&bo->vmap, PXP_BB_SIZE); + gsc_res->msg_out = IOSYS_MAP_INIT_OFFSET(&bo->vmap, PXP_BB_SIZE + inout_size); + gsc_res->q = q; + + /* initialize host-session-handle (for all Xe-to-gsc-firmware PXP cmds) */ + gsc_res->host_session_handle = xe_gsc_create_host_session_id(); + + return 0; + +bo_out: + xe_bo_unpin_map_no_vm(bo); +vm_out: + xe_vm_close_and_put(vm); + + return err; +} + +static void destroy_gsc_client_resources(struct xe_pxp_gsc_client_resources *gsc_res) +{ + if (!gsc_res->q) + return; + + xe_exec_queue_put(gsc_res->q); + xe_bo_unpin_map_no_vm(gsc_res->bo); + xe_vm_close_and_put(gsc_res->vm); +} + +/** + * xe_pxp_allocate_execution_resources - Allocate PXP submission objects + * @pxp: the xe_pxp structure + * + * Allocates exec_queues objects for VCS and GSCCS submission. The GSCCS + * submissions are done via PPGTT, so this function allocates a VM for it and + * maps the object into it. + * + * Returns 0 if the allocation and mapping is successful, an errno value + * otherwise. + */ +int xe_pxp_allocate_execution_resources(struct xe_pxp *pxp) +{ + int err; + + err = allocate_vcs_execution_resources(pxp); + if (err) + return err; + + /* + * PXP commands can require a lot of BO space (see PXP_MAX_PACKET_SIZE), + * but we currently only support a subset of commands that are small + * (< 20 dwords), so a single page is enough for now. + */ + err = allocate_gsc_client_resources(pxp->gt, &pxp->gsc_res, XE_PAGE_SIZE); + if (err) + goto destroy_vcs_context; + + return 0; + +destroy_vcs_context: + destroy_vcs_execution_resources(pxp); + return err; +} + +void xe_pxp_destroy_execution_resources(struct xe_pxp *pxp) +{ + destroy_gsc_client_resources(&pxp->gsc_res); + destroy_vcs_execution_resources(pxp); +} diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.h b/drivers/gpu/drm/xe/xe_pxp_submit.h new file mode 100644 index 0000000000000..fd21ac935be15 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pxp_submit.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright(c) 2024, Intel Corporation. All rights reserved. + */ + +#ifndef __XE_PXP_SUBMIT_H__ +#define __XE_PXP_SUBMIT_H__ + +struct xe_pxp; + +int xe_pxp_allocate_execution_resources(struct xe_pxp *pxp); +void xe_pxp_destroy_execution_resources(struct xe_pxp *pxp); + +#endif /* __XE_PXP_SUBMIT_H__ */ diff --git a/drivers/gpu/drm/xe/xe_pxp_types.h b/drivers/gpu/drm/xe/xe_pxp_types.h index 4639cf49d267b..0f86b50756cce 100644 --- a/drivers/gpu/drm/xe/xe_pxp_types.h +++ b/drivers/gpu/drm/xe/xe_pxp_types.h @@ -6,8 +6,45 @@ #ifndef __XE_PXP_TYPES_H__ #define __XE_PXP_TYPES_H__ +#include +#include + +struct xe_bo; +struct xe_exec_queue; struct xe_device; struct xe_gt; +struct xe_vm; + +/** + * struct xe_pxp_gsc_client_resources - resources for GSC submission by a PXP + * client. The GSC FW supports multiple GSC client active at the same time. + */ +struct xe_pxp_gsc_client_resources { + /** + * @host_session_handle: handle used to identify the client in messages + * sent to the GSC firmware. + */ + u64 host_session_handle; + /** @vm: VM used for PXP submissions to the GSCCS */ + struct xe_vm *vm; + /** @q: GSCCS exec queue for PXP submissions */ + struct xe_exec_queue *q; + + /** + * @bo: BO used for submissions to the GSCCS and GSC FW. It includes + * space for the GSCCS batch and the input/output buffers read/written + * by the FW + */ + struct xe_bo *bo; + /** @inout_size: size of each of the msg_in/out sections individually */ + u32 inout_size; + /** @batch: iosys_map to the batch memory within the BO */ + struct iosys_map batch; + /** @msg_in: iosys_map to the input memory within the BO */ + struct iosys_map msg_in; + /** @msg_out: iosys_map to the output memory within the BO */ + struct iosys_map msg_out; +}; /** * struct xe_pxp - pxp state @@ -21,6 +58,17 @@ struct xe_pxp { * (VDBOX, KCR and GSC) */ struct xe_gt *gt; + + /** @vcs_exec: kernel-owned objects for PXP submissions to the VCS */ + struct { + /** @vcs_exec.q: kernel-owned VCS exec queue used for PXP terminations */ + struct xe_exec_queue *q; + /** @vcs_exec.bo: BO used for submissions to the VCS */ + struct xe_bo *bo; + } vcs_exec; + + /** @gsc_res: kernel-owned objects for PXP submissions to the GSCCS */ + struct xe_pxp_gsc_client_resources gsc_res; }; #endif /* __XE_PXP_TYPES_H__ */ diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index 690330352d4cd..b9270d059e182 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -1382,6 +1382,12 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags) struct xe_tile *tile; u8 id; + /* + * Since the GSCCS is not user-accessible, we don't expect a GSC VM to + * ever be in faulting mode. + */ + xe_assert(xe, !((flags & XE_VM_FLAG_GSC) && (flags & XE_VM_FLAG_FAULT_MODE))); + vm = kzalloc(sizeof(*vm), GFP_KERNEL); if (!vm) return ERR_PTR(-ENOMEM); @@ -1392,7 +1398,21 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags) vm->flags = flags; - init_rwsem(&vm->lock); + /** + * GSC VMs are kernel-owned, only used for PXP ops and can sometimes be + * manipulated under the PXP mutex. However, the PXP mutex can be taken + * under a user-VM lock when the PXP session is started at exec_queue + * creation time. Those are different VMs and therefore there is no risk + * of deadlock, but we need to tell lockdep that this is the case or it + * will print a warning. + */ + if (flags & XE_VM_FLAG_GSC) { + static struct lock_class_key gsc_vm_key; + + __init_rwsem(&vm->lock, "gsc_vm", &gsc_vm_key); + } else { + init_rwsem(&vm->lock); + } mutex_init(&vm->snap_mutex); INIT_LIST_HEAD(&vm->rebind_list); @@ -2668,11 +2688,10 @@ static void vm_bind_ioctl_ops_fini(struct xe_vm *vm, struct xe_vma_ops *vops, for (i = 0; i < vops->num_syncs; i++) xe_sync_entry_signal(vops->syncs + i, fence); xe_exec_queue_last_fence_set(wait_exec_queue, vm, fence); - dma_fence_put(fence); } -static int vm_bind_ioctl_ops_execute(struct xe_vm *vm, - struct xe_vma_ops *vops) +static struct dma_fence *vm_bind_ioctl_ops_execute(struct xe_vm *vm, + struct xe_vma_ops *vops) { struct drm_exec exec; struct dma_fence *fence; @@ -2685,21 +2704,21 @@ static int vm_bind_ioctl_ops_execute(struct xe_vm *vm, drm_exec_until_all_locked(&exec) { err = vm_bind_ioctl_ops_lock_and_prep(&exec, vm, vops); drm_exec_retry_on_contention(&exec); - if (err) + if (err) { + fence = ERR_PTR(err); goto unlock; + } fence = ops_execute(vm, vops); - if (IS_ERR(fence)) { - err = PTR_ERR(fence); + if (IS_ERR(fence)) goto unlock; - } vm_bind_ioctl_ops_fini(vm, vops, fence); } unlock: drm_exec_fini(&exec); - return err; + return fence; } ALLOW_ERROR_INJECTION(vm_bind_ioctl_ops_execute, ERRNO); @@ -2931,6 +2950,7 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file) struct xe_sync_entry *syncs = NULL; struct drm_xe_vm_bind_op *bind_ops; struct xe_vma_ops vops; + struct dma_fence *fence; int err; int i; @@ -3095,7 +3115,11 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file) if (err) goto unwind_ops; - err = vm_bind_ioctl_ops_execute(vm, &vops); + fence = vm_bind_ioctl_ops_execute(vm, &vops); + if (IS_ERR(fence)) + err = PTR_ERR(fence); + else + dma_fence_put(fence); unwind_ops: if (err && err != -ENODATA) @@ -3129,6 +3153,81 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file) return err; } +/** + * xe_vm_bind_kernel_bo - bind a kernel BO to a VM + * @vm: VM to bind the BO to + * @bo: BO to bind + * @q: exec queue to use for the bind (optional) + * @addr: address at which to bind the BO + * @cache_lvl: PAT cache level to use + * + * Execute a VM bind map operation on a kernel-owned BO to bind it into a + * kernel-owned VM. + * + * Returns a dma_fence to track the binding completion if the job to do so was + * successfully submitted, an error pointer otherwise. + */ +struct dma_fence *xe_vm_bind_kernel_bo(struct xe_vm *vm, struct xe_bo *bo, + struct xe_exec_queue *q, u64 addr, + enum xe_cache_level cache_lvl) +{ + struct xe_vma_ops vops; + struct drm_gpuva_ops *ops = NULL; + struct dma_fence *fence; + int err; + + xe_bo_get(bo); + xe_vm_get(vm); + if (q) + xe_exec_queue_get(q); + + down_write(&vm->lock); + + xe_vma_ops_init(&vops, vm, q, NULL, 0); + + ops = vm_bind_ioctl_ops_create(vm, bo, 0, addr, bo->size, + DRM_XE_VM_BIND_OP_MAP, 0, 0, + vm->xe->pat.idx[cache_lvl]); + if (IS_ERR(ops)) { + err = PTR_ERR(ops); + goto release_vm_lock; + } + + err = vm_bind_ioctl_ops_parse(vm, ops, &vops); + if (err) + goto release_vm_lock; + + xe_assert(vm->xe, !list_empty(&vops.list)); + + err = xe_vma_ops_alloc(&vops, false); + if (err) + goto unwind_ops; + + fence = vm_bind_ioctl_ops_execute(vm, &vops); + if (IS_ERR(fence)) + err = PTR_ERR(fence); + +unwind_ops: + if (err && err != -ENODATA) + vm_bind_ioctl_ops_unwind(vm, &ops, 1); + + xe_vma_ops_fini(&vops); + drm_gpuva_ops_free(&vm->gpuvm, ops); + +release_vm_lock: + up_write(&vm->lock); + + if (q) + xe_exec_queue_put(q); + xe_vm_put(vm); + xe_bo_put(bo); + + if (err) + fence = ERR_PTR(err); + + return fence; +} + /** * xe_vm_lock() - Lock the vm's dma_resv object * @vm: The struct xe_vm whose lock is to be locked diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h index 23adb74428815..0a2fa6c0815b7 100644 --- a/drivers/gpu/drm/xe/xe_vm.h +++ b/drivers/gpu/drm/xe/xe_vm.h @@ -18,6 +18,8 @@ struct drm_file; struct ttm_buffer_object; +struct dma_fence; + struct xe_exec_queue; struct xe_file; struct xe_sync_entry; @@ -247,6 +249,10 @@ int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma); int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec, unsigned int num_fences); +struct dma_fence *xe_vm_bind_kernel_bo(struct xe_vm *vm, struct xe_bo *bo, + struct xe_exec_queue *q, u64 addr, + enum xe_cache_level cache_lvl); + /** * xe_vm_resv() - Return's the vm's reservation object * @vm: The vm diff --git a/drivers/gpu/drm/xe/xe_vm_types.h b/drivers/gpu/drm/xe/xe_vm_types.h index 7f9a303e51d89..52467b9b5348f 100644 --- a/drivers/gpu/drm/xe/xe_vm_types.h +++ b/drivers/gpu/drm/xe/xe_vm_types.h @@ -164,6 +164,7 @@ struct xe_vm { #define XE_VM_FLAG_BANNED BIT(5) #define XE_VM_FLAG_TILE_ID(flags) FIELD_GET(GENMASK(7, 6), flags) #define XE_VM_FLAG_SET_TILE_ID(tile) FIELD_PREP(GENMASK(7, 6), (tile)->id) +#define XE_VM_FLAG_GSC BIT(8) unsigned long flags; /** @composite_fence_ctx: context composite fence */ From f0c06677d1105a599370ffd0c94679996c3656f2 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:27 -0800 Subject: [PATCH 073/130] drm/xe/pxp: Add VCS inline termination support The key termination is done with a specific submission to the VCS engine. This flow will be triggered in response to a termination interrupt, whose handling is coming in a follow-up patch in the series. v2: clean up defines and command emission code. (John) Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-4-daniele.ceraolospurio@intel.com --- .../gpu/drm/xe/instructions/xe_instr_defs.h | 1 + .../gpu/drm/xe/instructions/xe_mfx_commands.h | 28 +++++ .../gpu/drm/xe/instructions/xe_mi_commands.h | 5 + drivers/gpu/drm/xe/xe_lrc.h | 3 +- drivers/gpu/drm/xe/xe_pxp_submit.c | 114 ++++++++++++++++++ drivers/gpu/drm/xe/xe_pxp_submit.h | 4 + drivers/gpu/drm/xe/xe_ring_ops.c | 4 +- 7 files changed, 156 insertions(+), 3 deletions(-) create mode 100644 drivers/gpu/drm/xe/instructions/xe_mfx_commands.h diff --git a/drivers/gpu/drm/xe/instructions/xe_instr_defs.h b/drivers/gpu/drm/xe/instructions/xe_instr_defs.h index fd2ce7ace5108..e559969468c44 100644 --- a/drivers/gpu/drm/xe/instructions/xe_instr_defs.h +++ b/drivers/gpu/drm/xe/instructions/xe_instr_defs.h @@ -16,6 +16,7 @@ #define XE_INSTR_CMD_TYPE GENMASK(31, 29) #define XE_INSTR_MI REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x0) #define XE_INSTR_GSC REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x2) +#define XE_INSTR_VIDEOPIPE REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x3) #define XE_INSTR_GFXPIPE REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x3) #define XE_INSTR_GFX_STATE REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x4) diff --git a/drivers/gpu/drm/xe/instructions/xe_mfx_commands.h b/drivers/gpu/drm/xe/instructions/xe_mfx_commands.h new file mode 100644 index 0000000000000..3c0c97f78e908 --- /dev/null +++ b/drivers/gpu/drm/xe/instructions/xe_mfx_commands.h @@ -0,0 +1,28 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2024 Intel Corporation + */ + +#ifndef _XE_MFX_COMMANDS_H_ +#define _XE_MFX_COMMANDS_H_ + +#include "instructions/xe_instr_defs.h" + +#define MFX_CMD_SUBTYPE REG_GENMASK(28, 27) /* A.K.A cmd pipe */ +#define MFX_CMD_OPCODE REG_GENMASK(26, 24) +#define MFX_CMD_SUB_OPCODE REG_GENMASK(23, 16) +#define MFX_FLAGS_AND_LEN REG_GENMASK(15, 0) + +#define XE_MFX_INSTR(subtype, op, sub_op) \ + (XE_INSTR_VIDEOPIPE | \ + REG_FIELD_PREP(MFX_CMD_SUBTYPE, subtype) | \ + REG_FIELD_PREP(MFX_CMD_OPCODE, op) | \ + REG_FIELD_PREP(MFX_CMD_SUB_OPCODE, sub_op)) + +#define MFX_WAIT XE_MFX_INSTR(1, 0, 0) +#define MFX_WAIT_DW0_PXP_SYNC_CONTROL_FLAG REG_BIT(9) +#define MFX_WAIT_DW0_MFX_SYNC_CONTROL_FLAG REG_BIT(8) + +#define CRYPTO_KEY_EXCHANGE XE_MFX_INSTR(2, 6, 9) + +#endif diff --git a/drivers/gpu/drm/xe/instructions/xe_mi_commands.h b/drivers/gpu/drm/xe/instructions/xe_mi_commands.h index 10ec2920d31b3..167fb0f742de7 100644 --- a/drivers/gpu/drm/xe/instructions/xe_mi_commands.h +++ b/drivers/gpu/drm/xe/instructions/xe_mi_commands.h @@ -48,6 +48,7 @@ #define MI_LRI_LEN(x) (((x) & 0xff) + 1) #define MI_FLUSH_DW __MI_INSTR(0x26) +#define MI_FLUSH_DW_PROTECTED_MEM_EN REG_BIT(22) #define MI_FLUSH_DW_STORE_INDEX REG_BIT(21) #define MI_INVALIDATE_TLB REG_BIT(18) #define MI_FLUSH_DW_CCS REG_BIT(16) @@ -66,4 +67,8 @@ #define MI_BATCH_BUFFER_START __MI_INSTR(0x31) +#define MI_SET_APPID __MI_INSTR(0x0e) +#define MI_SET_APPID_SESSION_ID_MASK REG_GENMASK(6, 0) +#define MI_SET_APPID_SESSION_ID(x) REG_FIELD_PREP(MI_SET_APPID_SESSION_ID_MASK, x) + #endif diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h index 4206e6a8b50a0..b27e80cd842ac 100644 --- a/drivers/gpu/drm/xe/xe_lrc.h +++ b/drivers/gpu/drm/xe/xe_lrc.h @@ -39,7 +39,8 @@ struct xe_lrc_snapshot { u32 ctx_job_timestamp; }; -#define LRC_PPHWSP_SCRATCH_ADDR (0x34 * 4) +#define LRC_PPHWSP_FLUSH_INVAL_SCRATCH_ADDR (0x34 * 4) +#define LRC_PPHWSP_PXP_INVAL_SCRATCH_ADDR (0x40 * 4) struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, u32 ring_size, u16 msix_vec); diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.c b/drivers/gpu/drm/xe/xe_pxp_submit.c index 52a6143b5ebe8..326baea679a35 100644 --- a/drivers/gpu/drm/xe/xe_pxp_submit.c +++ b/drivers/gpu/drm/xe/xe_pxp_submit.c @@ -5,15 +5,21 @@ #include "xe_pxp_submit.h" +#include #include #include "xe_device_types.h" +#include "xe_bb.h" #include "xe_bo.h" #include "xe_exec_queue.h" #include "xe_gsc_submit.h" #include "xe_gt.h" +#include "xe_lrc.h" #include "xe_pxp_types.h" +#include "xe_sched_job.h" #include "xe_vm.h" +#include "instructions/xe_mfx_commands.h" +#include "instructions/xe_mi_commands.h" /* * The VCS is used for kernel-owned GGTT submissions to issue key termination. @@ -197,3 +203,111 @@ void xe_pxp_destroy_execution_resources(struct xe_pxp *pxp) destroy_gsc_client_resources(&pxp->gsc_res); destroy_vcs_execution_resources(pxp); } + +#define emit_cmd(xe_, map_, offset_, val_) \ + xe_map_wr(xe_, map_, (offset_) * sizeof(u32), u32, val_) + +/* stall until prior PXP and MFX/HCP/HUC objects are completed */ +#define MFX_WAIT_PXP (MFX_WAIT | \ + MFX_WAIT_DW0_PXP_SYNC_CONTROL_FLAG | \ + MFX_WAIT_DW0_MFX_SYNC_CONTROL_FLAG) +static u32 pxp_emit_wait(struct xe_device *xe, struct iosys_map *batch, u32 offset) +{ + /* wait for cmds to go through */ + emit_cmd(xe, batch, offset++, MFX_WAIT_PXP); + emit_cmd(xe, batch, offset++, 0); + + return offset; +} + +static u32 pxp_emit_session_selection(struct xe_device *xe, struct iosys_map *batch, + u32 offset, u32 idx) +{ + offset = pxp_emit_wait(xe, batch, offset); + + /* pxp off */ + emit_cmd(xe, batch, offset++, MI_FLUSH_DW | MI_FLUSH_IMM_DW); + emit_cmd(xe, batch, offset++, 0); + emit_cmd(xe, batch, offset++, 0); + emit_cmd(xe, batch, offset++, 0); + + /* select session */ + emit_cmd(xe, batch, offset++, MI_SET_APPID | MI_SET_APPID_SESSION_ID(idx)); + emit_cmd(xe, batch, offset++, 0); + + offset = pxp_emit_wait(xe, batch, offset); + + /* pxp on */ + emit_cmd(xe, batch, offset++, MI_FLUSH_DW | + MI_FLUSH_DW_PROTECTED_MEM_EN | + MI_FLUSH_DW_OP_STOREDW | MI_FLUSH_DW_STORE_INDEX | + MI_FLUSH_IMM_DW); + emit_cmd(xe, batch, offset++, LRC_PPHWSP_PXP_INVAL_SCRATCH_ADDR | + MI_FLUSH_DW_USE_GTT); + emit_cmd(xe, batch, offset++, 0); + emit_cmd(xe, batch, offset++, 0); + + offset = pxp_emit_wait(xe, batch, offset); + + return offset; +} + +static u32 pxp_emit_inline_termination(struct xe_device *xe, + struct iosys_map *batch, u32 offset) +{ + /* session inline termination */ + emit_cmd(xe, batch, offset++, CRYPTO_KEY_EXCHANGE); + emit_cmd(xe, batch, offset++, 0); + + return offset; +} + +static u32 pxp_emit_session_termination(struct xe_device *xe, struct iosys_map *batch, + u32 offset, u32 idx) +{ + offset = pxp_emit_session_selection(xe, batch, offset, idx); + offset = pxp_emit_inline_termination(xe, batch, offset); + + return offset; +} + +/** + * xe_pxp_submit_session_termination - submits a PXP inline termination + * @pxp: the xe_pxp structure + * @id: the session to terminate + * + * Emit an inline termination via the VCS engine to terminate a session. + * + * Returns 0 if the submission is successful, an errno value otherwise. + */ +int xe_pxp_submit_session_termination(struct xe_pxp *pxp, u32 id) +{ + struct xe_sched_job *job; + struct dma_fence *fence; + long timeout; + u32 offset = 0; + u64 addr = xe_bo_ggtt_addr(pxp->vcs_exec.bo); + + offset = pxp_emit_session_termination(pxp->xe, &pxp->vcs_exec.bo->vmap, offset, id); + offset = pxp_emit_wait(pxp->xe, &pxp->vcs_exec.bo->vmap, offset); + emit_cmd(pxp->xe, &pxp->vcs_exec.bo->vmap, offset, MI_BATCH_BUFFER_END); + + job = xe_sched_job_create(pxp->vcs_exec.q, &addr); + if (IS_ERR(job)) + return PTR_ERR(job); + + xe_sched_job_arm(job); + fence = dma_fence_get(&job->drm.s_fence->finished); + xe_sched_job_push(job); + + timeout = dma_fence_wait_timeout(fence, false, HZ); + + dma_fence_put(fence); + + if (!timeout) + return -ETIMEDOUT; + else if (timeout < 0) + return timeout; + + return 0; +} diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.h b/drivers/gpu/drm/xe/xe_pxp_submit.h index fd21ac935be15..4ee8c0acfed99 100644 --- a/drivers/gpu/drm/xe/xe_pxp_submit.h +++ b/drivers/gpu/drm/xe/xe_pxp_submit.h @@ -6,9 +6,13 @@ #ifndef __XE_PXP_SUBMIT_H__ #define __XE_PXP_SUBMIT_H__ +#include + struct xe_pxp; int xe_pxp_allocate_execution_resources(struct xe_pxp *pxp); void xe_pxp_destroy_execution_resources(struct xe_pxp *pxp); +int xe_pxp_submit_session_termination(struct xe_pxp *pxp, u32 id); + #endif /* __XE_PXP_SUBMIT_H__ */ diff --git a/drivers/gpu/drm/xe/xe_ring_ops.c b/drivers/gpu/drm/xe/xe_ring_ops.c index 9f327f27c0726..0c230ee53bba5 100644 --- a/drivers/gpu/drm/xe/xe_ring_ops.c +++ b/drivers/gpu/drm/xe/xe_ring_ops.c @@ -118,7 +118,7 @@ static int emit_flush_invalidate(u32 flag, u32 *dw, int i) dw[i++] |= MI_INVALIDATE_TLB | MI_FLUSH_DW_OP_STOREDW | MI_FLUSH_IMM_DW | MI_FLUSH_DW_STORE_INDEX; - dw[i++] = LRC_PPHWSP_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT; + dw[i++] = LRC_PPHWSP_FLUSH_INVAL_SCRATCH_ADDR | MI_FLUSH_DW_USE_GTT; dw[i++] = 0; dw[i++] = ~0U; @@ -156,7 +156,7 @@ static int emit_pipe_invalidate(u32 mask_flags, bool invalidate_tlb, u32 *dw, flags &= ~mask_flags; - return emit_pipe_control(dw, i, 0, flags, LRC_PPHWSP_SCRATCH_ADDR, 0); + return emit_pipe_control(dw, i, 0, flags, LRC_PPHWSP_FLUSH_INVAL_SCRATCH_ADDR, 0); } static int emit_store_imm_ppgtt_posted(u64 addr, u64 value, From 96e84a2f5a5ba0efaaefb0dd5072e4b2e7f31f0e Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:28 -0800 Subject: [PATCH 074/130] drm/xe/pxp: Add GSC session invalidation support After a session is terminated, we need to inform the GSC so that it can clean up its side of the allocation. This is done by sending an invalidation command with the session ID. The invalidation will be triggered in response to a termination, interrupt, whose handling is coming in the next patch in the series. v2: Better comment and error messages (John) Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-5-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h | 13 + drivers/gpu/drm/xe/xe_pxp_submit.c | 228 ++++++++++++++++++ drivers/gpu/drm/xe/xe_pxp_submit.h | 3 + 3 files changed, 244 insertions(+) diff --git a/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h b/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h index f3c4cf10ba208..f0da65ccdda23 100644 --- a/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h +++ b/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h @@ -31,6 +31,7 @@ enum pxp_status { PXP_STATUS_NOT_READY = 0x100e, PXP_STATUS_PLATFCONFIG_KF1_NOVERIF = 0x101a, PXP_STATUS_PLATFCONFIG_KF1_BAD = 0x101f, + PXP_STATUS_PLATFCONFIG_FIXED_KF1_NOT_SUPPORTED = 0x1037, PXP_STATUS_OP_NOT_PERMITTED = 0x4013 }; @@ -49,6 +50,7 @@ struct pxp_cmd_header { u32 buffer_len; } __packed; +#define PXP43_CMDID_INVALIDATE_STREAM_KEY 0x00000007 #define PXP43_CMDID_NEW_HUC_AUTH 0x0000003F /* MTL+ */ /* PXP-Input-Packet: HUC Auth-only */ @@ -63,4 +65,15 @@ struct pxp43_huc_auth_out { struct pxp_cmd_header header; } __packed; +/* PXP-Input-Packet: Invalidate Stream Key */ +struct pxp43_inv_stream_key_in { + struct pxp_cmd_header header; + u32 rsvd[3]; +} __packed; + +/* PXP-Output-Packet: Invalidate Stream Key */ +struct pxp43_inv_stream_key_out { + struct pxp_cmd_header header; + u32 rsvd; +} __packed; #endif diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.c b/drivers/gpu/drm/xe/xe_pxp_submit.c index 326baea679a35..f5f6b18c10548 100644 --- a/drivers/gpu/drm/xe/xe_pxp_submit.c +++ b/drivers/gpu/drm/xe/xe_pxp_submit.c @@ -15,9 +15,13 @@ #include "xe_gsc_submit.h" #include "xe_gt.h" #include "xe_lrc.h" +#include "xe_map.h" #include "xe_pxp_types.h" #include "xe_sched_job.h" #include "xe_vm.h" +#include "abi/gsc_command_header_abi.h" +#include "abi/gsc_pxp_commands_abi.h" +#include "instructions/xe_gsc_commands.h" #include "instructions/xe_mfx_commands.h" #include "instructions/xe_mi_commands.h" @@ -311,3 +315,227 @@ int xe_pxp_submit_session_termination(struct xe_pxp *pxp, u32 id) return 0; } + +static bool +is_fw_err_platform_config(u32 type) +{ + switch (type) { + case PXP_STATUS_ERROR_API_VERSION: + case PXP_STATUS_PLATFCONFIG_KF1_NOVERIF: + case PXP_STATUS_PLATFCONFIG_KF1_BAD: + case PXP_STATUS_PLATFCONFIG_FIXED_KF1_NOT_SUPPORTED: + return true; + default: + break; + } + return false; +} + +static const char * +fw_err_to_string(u32 type) +{ + switch (type) { + case PXP_STATUS_ERROR_API_VERSION: + return "ERR_API_VERSION"; + case PXP_STATUS_NOT_READY: + return "ERR_NOT_READY"; + case PXP_STATUS_PLATFCONFIG_KF1_NOVERIF: + case PXP_STATUS_PLATFCONFIG_KF1_BAD: + case PXP_STATUS_PLATFCONFIG_FIXED_KF1_NOT_SUPPORTED: + return "ERR_PLATFORM_CONFIG"; + default: + break; + } + return NULL; +} + +static int pxp_pkt_submit(struct xe_exec_queue *q, u64 batch_addr) +{ + struct xe_gt *gt = q->gt; + struct xe_device *xe = gt_to_xe(gt); + struct xe_sched_job *job; + struct dma_fence *fence; + long timeout; + + xe_assert(xe, q->hwe->engine_id == XE_HW_ENGINE_GSCCS0); + + job = xe_sched_job_create(q, &batch_addr); + if (IS_ERR(job)) + return PTR_ERR(job); + + xe_sched_job_arm(job); + fence = dma_fence_get(&job->drm.s_fence->finished); + xe_sched_job_push(job); + + timeout = dma_fence_wait_timeout(fence, false, HZ); + dma_fence_put(fence); + if (timeout < 0) + return timeout; + else if (!timeout) + return -ETIME; + + return 0; +} + +static void emit_pxp_heci_cmd(struct xe_device *xe, struct iosys_map *batch, + u64 addr_in, u32 size_in, u64 addr_out, u32 size_out) +{ + u32 len = 0; + + xe_map_wr(xe, batch, len++ * sizeof(u32), u32, GSC_HECI_CMD_PKT); + xe_map_wr(xe, batch, len++ * sizeof(u32), u32, lower_32_bits(addr_in)); + xe_map_wr(xe, batch, len++ * sizeof(u32), u32, upper_32_bits(addr_in)); + xe_map_wr(xe, batch, len++ * sizeof(u32), u32, size_in); + xe_map_wr(xe, batch, len++ * sizeof(u32), u32, lower_32_bits(addr_out)); + xe_map_wr(xe, batch, len++ * sizeof(u32), u32, upper_32_bits(addr_out)); + xe_map_wr(xe, batch, len++ * sizeof(u32), u32, size_out); + xe_map_wr(xe, batch, len++ * sizeof(u32), u32, 0); + xe_map_wr(xe, batch, len++ * sizeof(u32), u32, MI_BATCH_BUFFER_END); +} + +#define GSC_PENDING_RETRY_MAXCOUNT 40 +#define GSC_PENDING_RETRY_PAUSE_MS 50 +static int gsccs_send_message(struct xe_pxp_gsc_client_resources *gsc_res, + void *msg_in, size_t msg_in_size, + void *msg_out, size_t msg_out_size_max) +{ + struct xe_device *xe = gsc_res->vm->xe; + const size_t max_msg_size = gsc_res->inout_size - sizeof(struct intel_gsc_mtl_header); + u32 wr_offset; + u32 rd_offset; + u32 reply_size; + u32 min_reply_size = 0; + int ret; + int retry = GSC_PENDING_RETRY_MAXCOUNT; + + if (msg_in_size > max_msg_size || msg_out_size_max > max_msg_size) + return -ENOSPC; + + wr_offset = xe_gsc_emit_header(xe, &gsc_res->msg_in, 0, + HECI_MEADDRESS_PXP, + gsc_res->host_session_handle, + msg_in_size); + + /* NOTE: zero size packets are used for session-cleanups */ + if (msg_in && msg_in_size) { + xe_map_memcpy_to(xe, &gsc_res->msg_in, wr_offset, + msg_in, msg_in_size); + min_reply_size = sizeof(struct pxp_cmd_header); + } + + /* Make sure the reply header does not contain stale data */ + xe_gsc_poison_header(xe, &gsc_res->msg_out, 0); + + /* + * The BO is mapped at address 0 of the PPGTT, so no need to add its + * base offset when calculating the in/out addresses. + */ + emit_pxp_heci_cmd(xe, &gsc_res->batch, PXP_BB_SIZE, + wr_offset + msg_in_size, PXP_BB_SIZE + gsc_res->inout_size, + wr_offset + msg_out_size_max); + + xe_device_wmb(xe); + + /* + * If the GSC needs to communicate with CSME to complete our request, + * it'll set the "pending" flag in the return header. In this scenario + * we're expected to wait 50ms to give some time to the proxy code to + * handle the GSC<->CSME communication and then try again. Note that, + * although in most case the 50ms window is enough, the proxy flow is + * not actually guaranteed to complete within that time period, so we + * might have to try multiple times, up to a worst case of 2 seconds, + * after which the request is considered aborted. + */ + do { + ret = pxp_pkt_submit(gsc_res->q, 0); + if (ret) + break; + + if (xe_gsc_check_and_update_pending(xe, &gsc_res->msg_in, 0, + &gsc_res->msg_out, 0)) { + ret = -EAGAIN; + msleep(GSC_PENDING_RETRY_PAUSE_MS); + } + } while (--retry && ret == -EAGAIN); + + if (ret) { + drm_err(&xe->drm, "failed to submit GSC PXP message (%pe)\n", ERR_PTR(ret)); + return ret; + } + + ret = xe_gsc_read_out_header(xe, &gsc_res->msg_out, 0, + min_reply_size, &rd_offset); + if (ret) { + drm_err(&xe->drm, "invalid GSC reply for PXP (%pe)\n", ERR_PTR(ret)); + return ret; + } + + if (msg_out && min_reply_size) { + reply_size = xe_map_rd_field(xe, &gsc_res->msg_out, rd_offset, + struct pxp_cmd_header, buffer_len); + reply_size += sizeof(struct pxp_cmd_header); + + if (reply_size > msg_out_size_max) { + drm_warn(&xe->drm, "PXP reply size overflow: %u (%zu)\n", + reply_size, msg_out_size_max); + reply_size = msg_out_size_max; + } + + xe_map_memcpy_from(xe, msg_out, &gsc_res->msg_out, + rd_offset, reply_size); + } + + xe_gsc_poison_header(xe, &gsc_res->msg_in, 0); + + return ret; +} + +/** + * xe_pxp_submit_session_invalidation - submits a PXP GSC invalidation + * @gsc_res: the pxp client resources + * @id: the session to invalidate + * + * Submit a message to the GSC FW to notify it that a session has been + * terminated and is therefore invalid. + * + * Returns 0 if the submission is successful, an errno value otherwise. + */ +int xe_pxp_submit_session_invalidation(struct xe_pxp_gsc_client_resources *gsc_res, u32 id) +{ + struct xe_device *xe = gsc_res->vm->xe; + struct pxp43_inv_stream_key_in msg_in = {0}; + struct pxp43_inv_stream_key_out msg_out = {0}; + int ret = 0; + + /* + * Stream key invalidation reuses the same version 4.2 input/output + * command format but firmware requires 4.3 API interaction + */ + msg_in.header.api_version = PXP_APIVER(4, 3); + msg_in.header.command_id = PXP43_CMDID_INVALIDATE_STREAM_KEY; + msg_in.header.buffer_len = sizeof(msg_in) - sizeof(msg_in.header); + + msg_in.header.stream_id = FIELD_PREP(PXP_CMDHDR_EXTDATA_SESSION_VALID, 1); + msg_in.header.stream_id |= FIELD_PREP(PXP_CMDHDR_EXTDATA_APP_TYPE, 0); + msg_in.header.stream_id |= FIELD_PREP(PXP_CMDHDR_EXTDATA_SESSION_ID, id); + + ret = gsccs_send_message(gsc_res, &msg_in, sizeof(msg_in), + &msg_out, sizeof(msg_out)); + if (ret) { + drm_err(&xe->drm, "Failed to invalidate PXP stream-key %u (%pe)\n", + id, ERR_PTR(ret)); + } else if (msg_out.header.status != 0) { + ret = -EIO; + + if (is_fw_err_platform_config(msg_out.header.status)) + drm_info_once(&xe->drm, + "Failed to invalidate PXP stream-key %u: BIOS/SOC 0x%08x(%s)\n", + id, msg_out.header.status, + fw_err_to_string(msg_out.header.status)); + else + drm_dbg(&xe->drm, "Failed to invalidate stream-key %u, s=0x%08x\n", + id, msg_out.header.status); + } + + return ret; +} diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.h b/drivers/gpu/drm/xe/xe_pxp_submit.h index 4ee8c0acfed99..48fdc9b091163 100644 --- a/drivers/gpu/drm/xe/xe_pxp_submit.h +++ b/drivers/gpu/drm/xe/xe_pxp_submit.h @@ -9,10 +9,13 @@ #include struct xe_pxp; +struct xe_pxp_gsc_client_resources; int xe_pxp_allocate_execution_resources(struct xe_pxp *pxp); void xe_pxp_destroy_execution_resources(struct xe_pxp *pxp); int xe_pxp_submit_session_termination(struct xe_pxp *pxp, u32 id); +int xe_pxp_submit_session_invalidation(struct xe_pxp_gsc_client_resources *gsc_res, + u32 id); #endif /* __XE_PXP_SUBMIT_H__ */ From 3b506d73ec14977f3107ade94346cfb169c6f3b9 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:29 -0800 Subject: [PATCH 075/130] drm/xe/pxp: Handle the PXP termination interrupt When something happen to the session, the HW generates a termination interrupt. In reply to this, the driver is required to submit an inline session termination via the VCS, trigger the global termination and notify the GSC FW that the session is now invalid. v2: rename ARB define to make it cleaner to move it to uapi (John) v3: fix parameter name in documentation Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-6-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/regs/xe_irq_regs.h | 8 ++ drivers/gpu/drm/xe/regs/xe_pxp_regs.h | 6 ++ drivers/gpu/drm/xe/xe_irq.c | 20 +++- drivers/gpu/drm/xe/xe_pxp.c | 139 +++++++++++++++++++++++++- drivers/gpu/drm/xe/xe_pxp.h | 7 ++ drivers/gpu/drm/xe/xe_pxp_types.h | 13 +++ 6 files changed, 189 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_irq_regs.h b/drivers/gpu/drm/xe/regs/xe_irq_regs.h index 1776b3f78ccb7..f0ecfcac40037 100644 --- a/drivers/gpu/drm/xe/regs/xe_irq_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_irq_regs.h @@ -44,6 +44,7 @@ #define ENGINE1_MASK REG_GENMASK(31, 16) #define ENGINE0_MASK REG_GENMASK(15, 0) #define GPM_WGBOXPERF_INTR_ENABLE XE_REG(0x19003c, XE_REG_OPTION_VF) +#define CRYPTO_RSVD_INTR_ENABLE XE_REG(0x190040) #define GUNIT_GSC_INTR_ENABLE XE_REG(0x190044, XE_REG_OPTION_VF) #define CCS_RSVD_INTR_ENABLE XE_REG(0x190048, XE_REG_OPTION_VF) @@ -54,6 +55,7 @@ #define INTR_ENGINE_INTR(x) REG_FIELD_GET(GENMASK(15, 0), x) #define OTHER_GUC_INSTANCE 0 #define OTHER_GSC_HECI2_INSTANCE 3 +#define OTHER_KCR_INSTANCE 4 #define OTHER_GSC_INSTANCE 6 #define IIR_REG_SELECTOR(x) XE_REG(0x190070 + ((x) * 4), XE_REG_OPTION_VF) @@ -65,6 +67,7 @@ #define HECI2_RSVD_INTR_MASK XE_REG(0x1900e4) #define GUC_SG_INTR_MASK XE_REG(0x1900e8, XE_REG_OPTION_VF) #define GPM_WGBOXPERF_INTR_MASK XE_REG(0x1900ec, XE_REG_OPTION_VF) +#define CRYPTO_RSVD_INTR_MASK XE_REG(0x1900f0) #define GUNIT_GSC_INTR_MASK XE_REG(0x1900f4, XE_REG_OPTION_VF) #define CCS0_CCS1_INTR_MASK XE_REG(0x190100) #define CCS2_CCS3_INTR_MASK XE_REG(0x190104) @@ -79,4 +82,9 @@ #define GT_CS_MASTER_ERROR_INTERRUPT REG_BIT(3) #define GT_RENDER_USER_INTERRUPT REG_BIT(0) +/* irqs for OTHER_KCR_INSTANCE */ +#define KCR_PXP_STATE_TERMINATED_INTERRUPT REG_BIT(1) +#define KCR_APP_TERMINATED_PER_FW_REQ_INTERRUPT REG_BIT(2) +#define KCR_PXP_STATE_RESET_COMPLETE_INTERRUPT REG_BIT(3) + #endif diff --git a/drivers/gpu/drm/xe/regs/xe_pxp_regs.h b/drivers/gpu/drm/xe/regs/xe_pxp_regs.h index d67cf210d23d5..aa158938b42eb 100644 --- a/drivers/gpu/drm/xe/regs/xe_pxp_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_pxp_regs.h @@ -14,4 +14,10 @@ #define KCR_INIT XE_REG(0x3860f0) #define KCR_INIT_ALLOW_DISPLAY_ME_WRITES REG_BIT(14) +/* KCR hwdrm session in play status 0-31 */ +#define KCR_SIP XE_REG(0x386260) + +/* PXP global terminate register for session termination */ +#define KCR_GLOBAL_TERMINATE XE_REG(0x3860f8) + #endif /* __XE_PXP_REGS_H__ */ diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c index 32f5a67a917b5..bf092e6391c7d 100644 --- a/drivers/gpu/drm/xe/xe_irq.c +++ b/drivers/gpu/drm/xe/xe_irq.c @@ -20,6 +20,7 @@ #include "xe_hw_engine.h" #include "xe_memirq.h" #include "xe_mmio.h" +#include "xe_pxp.h" #include "xe_sriov.h" /* @@ -208,6 +209,15 @@ void xe_irq_enable_hwe(struct xe_gt *gt) } if (heci_mask) xe_mmio_write32(mmio, HECI2_RSVD_INTR_MASK, ~(heci_mask << 16)); + + if (xe_pxp_is_supported(xe)) { + u32 kcr_mask = KCR_PXP_STATE_TERMINATED_INTERRUPT | + KCR_APP_TERMINATED_PER_FW_REQ_INTERRUPT | + KCR_PXP_STATE_RESET_COMPLETE_INTERRUPT; + + xe_mmio_write32(mmio, CRYPTO_RSVD_INTR_ENABLE, kcr_mask << 16); + xe_mmio_write32(mmio, CRYPTO_RSVD_INTR_MASK, ~(kcr_mask << 16)); + } } } @@ -330,9 +340,15 @@ static void gt_irq_handler(struct xe_tile *tile, } if (class == XE_ENGINE_CLASS_OTHER) { - /* HECI GSCFI interrupts come from outside of GT */ + /* + * HECI GSCFI interrupts come from outside of GT. + * KCR irqs come from inside GT but are handled + * by the global PXP subsystem. + */ if (xe->info.has_heci_gscfi && instance == OTHER_GSC_INSTANCE) xe_heci_gsc_irq_handler(xe, intr_vec); + else if (instance == OTHER_KCR_INSTANCE) + xe_pxp_irq_handler(xe, intr_vec); else gt_other_irq_handler(engine_gt, instance, intr_vec); } @@ -510,6 +526,8 @@ static void gt_irq_reset(struct xe_tile *tile) xe_mmio_write32(mmio, GUNIT_GSC_INTR_ENABLE, 0); xe_mmio_write32(mmio, GUNIT_GSC_INTR_MASK, ~0); xe_mmio_write32(mmio, HECI2_RSVD_INTR_MASK, ~0); + xe_mmio_write32(mmio, CRYPTO_RSVD_INTR_ENABLE, 0); + xe_mmio_write32(mmio, CRYPTO_RSVD_INTR_MASK, ~0); } xe_mmio_write32(mmio, GPM_WGBOXPERF_INTR_ENABLE, 0); diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 89d71a69cdff4..1452a4763ac2d 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -12,9 +12,11 @@ #include "xe_gt.h" #include "xe_gt_types.h" #include "xe_mmio.h" +#include "xe_pm.h" #include "xe_pxp_submit.h" #include "xe_pxp_types.h" #include "xe_uc_fw.h" +#include "regs/xe_irq_regs.h" #include "regs/xe_pxp_regs.h" /** @@ -25,11 +27,132 @@ * integrated parts. */ -static bool pxp_is_supported(const struct xe_device *xe) +#define ARB_SESSION DRM_XE_PXP_HWDRM_DEFAULT_SESSION /* shorter define */ + +bool xe_pxp_is_supported(const struct xe_device *xe) { return xe->info.has_pxp && IS_ENABLED(CONFIG_INTEL_MEI_GSC_PROXY); } +static bool pxp_is_enabled(const struct xe_pxp *pxp) +{ + return pxp; +} + +static int pxp_wait_for_session_state(struct xe_pxp *pxp, u32 id, bool in_play) +{ + struct xe_gt *gt = pxp->gt; + u32 mask = BIT(id); + + return xe_mmio_wait32(>->mmio, KCR_SIP, mask, in_play ? mask : 0, + 250, NULL, false); +} + +static void pxp_terminate(struct xe_pxp *pxp) +{ + int ret = 0; + struct xe_device *xe = pxp->xe; + struct xe_gt *gt = pxp->gt; + unsigned int fw_ref; + + drm_dbg(&xe->drm, "Terminating PXP\n"); + + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) { + ret = -EIO; + goto out; + } + + /* terminate the hw session */ + ret = xe_pxp_submit_session_termination(pxp, ARB_SESSION); + if (ret) + goto out; + + ret = pxp_wait_for_session_state(pxp, ARB_SESSION, false); + if (ret) + goto out; + + /* Trigger full HW cleanup */ + xe_mmio_write32(>->mmio, KCR_GLOBAL_TERMINATE, 1); + + /* now we can tell the GSC to clean up its own state */ + ret = xe_pxp_submit_session_invalidation(&pxp->gsc_res, ARB_SESSION); + +out: + xe_force_wake_put(gt_to_fw(gt), fw_ref); + + if (ret) + drm_err(&xe->drm, "PXP termination failed: %pe\n", ERR_PTR(ret)); +} + +static void pxp_terminate_complete(struct xe_pxp *pxp) +{ + /* TODO mark the session as ready to start */ +} + +static void pxp_irq_work(struct work_struct *work) +{ + struct xe_pxp *pxp = container_of(work, typeof(*pxp), irq.work); + struct xe_device *xe = pxp->xe; + u32 events = 0; + + spin_lock_irq(&xe->irq.lock); + events = pxp->irq.events; + pxp->irq.events = 0; + spin_unlock_irq(&xe->irq.lock); + + if (!events) + return; + + /* + * If we're processing a termination irq while suspending then don't + * bother, we're going to re-init everything on resume anyway. + */ + if ((events & PXP_TERMINATION_REQUEST) && !xe_pm_runtime_get_if_active(xe)) + return; + + if (events & PXP_TERMINATION_REQUEST) { + events &= ~PXP_TERMINATION_COMPLETE; + pxp_terminate(pxp); + } + + if (events & PXP_TERMINATION_COMPLETE) + pxp_terminate_complete(pxp); + + if (events & PXP_TERMINATION_REQUEST) + xe_pm_runtime_put(xe); +} + +/** + * xe_pxp_irq_handler - Handles PXP interrupts. + * @xe: the xe_device structure + * @iir: interrupt vector + */ +void xe_pxp_irq_handler(struct xe_device *xe, u16 iir) +{ + struct xe_pxp *pxp = xe->pxp; + + if (!pxp_is_enabled(pxp)) { + drm_err(&xe->drm, "PXP irq 0x%x received with PXP disabled!\n", iir); + return; + } + + lockdep_assert_held(&xe->irq.lock); + + if (unlikely(!iir)) + return; + + if (iir & (KCR_PXP_STATE_TERMINATED_INTERRUPT | + KCR_APP_TERMINATED_PER_FW_REQ_INTERRUPT)) + pxp->irq.events |= PXP_TERMINATION_REQUEST; + + if (iir & KCR_PXP_STATE_RESET_COMPLETE_INTERRUPT) + pxp->irq.events |= PXP_TERMINATION_COMPLETE; + + if (pxp->irq.events) + queue_work(pxp->irq.wq, &pxp->irq.work); +} + static int kcr_pxp_set_status(const struct xe_pxp *pxp, bool enable) { u32 val = enable ? _MASKED_BIT_ENABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES) : @@ -60,6 +183,7 @@ static void pxp_fini(void *arg) { struct xe_pxp *pxp = arg; + destroy_workqueue(pxp->irq.wq); xe_pxp_destroy_execution_resources(pxp); /* no need to explicitly disable KCR since we're going to do an FLR */ @@ -83,7 +207,7 @@ int xe_pxp_init(struct xe_device *xe) struct xe_pxp *pxp; int err; - if (!pxp_is_supported(xe)) + if (!xe_pxp_is_supported(xe)) return -EOPNOTSUPP; /* we only support PXP on single tile devices with a media GT */ @@ -105,12 +229,19 @@ int xe_pxp_init(struct xe_device *xe) if (!pxp) return -ENOMEM; + INIT_WORK(&pxp->irq.work, pxp_irq_work); pxp->xe = xe; pxp->gt = gt; + pxp->irq.wq = alloc_ordered_workqueue("pxp-wq", 0); + if (!pxp->irq.wq) { + err = -ENOMEM; + goto out_free; + } + err = kcr_pxp_enable(pxp); if (err) - goto out_free; + goto out_wq; err = xe_pxp_allocate_execution_resources(pxp); if (err) @@ -122,6 +253,8 @@ int xe_pxp_init(struct xe_device *xe) out_kcr_disable: kcr_pxp_disable(pxp); +out_wq: + destroy_workqueue(pxp->irq.wq); out_free: drmm_kfree(&xe->drm, pxp); return err; diff --git a/drivers/gpu/drm/xe/xe_pxp.h b/drivers/gpu/drm/xe/xe_pxp.h index 00f5e688c0d91..39435c644dcda 100644 --- a/drivers/gpu/drm/xe/xe_pxp.h +++ b/drivers/gpu/drm/xe/xe_pxp.h @@ -6,8 +6,15 @@ #ifndef __XE_PXP_H__ #define __XE_PXP_H__ +#include + struct xe_device; +#define DRM_XE_PXP_HWDRM_DEFAULT_SESSION 0xF /* TODO: move to uapi */ + +bool xe_pxp_is_supported(const struct xe_device *xe); + int xe_pxp_init(struct xe_device *xe); +void xe_pxp_irq_handler(struct xe_device *xe, u16 iir); #endif /* __XE_PXP_H__ */ diff --git a/drivers/gpu/drm/xe/xe_pxp_types.h b/drivers/gpu/drm/xe/xe_pxp_types.h index 0f86b50756cce..311d08111b5fa 100644 --- a/drivers/gpu/drm/xe/xe_pxp_types.h +++ b/drivers/gpu/drm/xe/xe_pxp_types.h @@ -8,6 +8,7 @@ #include #include +#include struct xe_bo; struct xe_exec_queue; @@ -69,6 +70,18 @@ struct xe_pxp { /** @gsc_res: kernel-owned objects for PXP submissions to the GSCCS */ struct xe_pxp_gsc_client_resources gsc_res; + + /** @irq: wrapper for the worker and queue used for PXP irq support */ + struct { + /** @irq.work: worker that manages irq events. */ + struct work_struct work; + /** @irq.wq: workqueue on which to queue the irq work. */ + struct workqueue_struct *wq; + /** @irq.events: pending events, protected with xe->irq.lock. */ + u32 events; +#define PXP_TERMINATION_REQUEST BIT(0) +#define PXP_TERMINATION_COMPLETE BIT(1) + } irq; }; #endif /* __XE_PXP_TYPES_H__ */ From 0387d46ea7fd0496375b8668385db16ce6172ece Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:30 -0800 Subject: [PATCH 076/130] drm/xe/pxp: Add GSC session initialization support A session is initialized (i.e. started) by sending a message to the GSC. The initialization will be triggered when a user opts-in to using PXP; the interface for that is coming in a follow-up patch in the series. v2: clean up error messages, use new ARB define (John) Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-7-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h | 21 +++++++++ drivers/gpu/drm/xe/xe_pxp_submit.c | 47 +++++++++++++++++++ drivers/gpu/drm/xe/xe_pxp_submit.h | 1 + 3 files changed, 69 insertions(+) diff --git a/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h b/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h index f0da65ccdda23..290e431cf10dd 100644 --- a/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h +++ b/drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h @@ -51,6 +51,7 @@ struct pxp_cmd_header { } __packed; #define PXP43_CMDID_INVALIDATE_STREAM_KEY 0x00000007 +#define PXP43_CMDID_INIT_SESSION 0x00000036 #define PXP43_CMDID_NEW_HUC_AUTH 0x0000003F /* MTL+ */ /* PXP-Input-Packet: HUC Auth-only */ @@ -65,6 +66,26 @@ struct pxp43_huc_auth_out { struct pxp_cmd_header header; } __packed; +/* PXP-Input-Packet: Init PXP session */ +struct pxp43_create_arb_in { + struct pxp_cmd_header header; + /* header.stream_id fields for vesion 4.3 of Init PXP session: */ + #define PXP43_INIT_SESSION_VALID BIT(0) + #define PXP43_INIT_SESSION_APPTYPE BIT(1) + #define PXP43_INIT_SESSION_APPID GENMASK(17, 2) + u32 protection_mode; + #define PXP43_INIT_SESSION_PROTECTION_ARB 0x2 + u32 sub_session_id; + u32 init_flags; + u32 rsvd[12]; +} __packed; + +/* PXP-Input-Packet: Init PXP session */ +struct pxp43_create_arb_out { + struct pxp_cmd_header header; + u32 rsvd[8]; +} __packed; + /* PXP-Input-Packet: Invalidate Stream Key */ struct pxp43_inv_stream_key_in { struct pxp_cmd_header header; diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.c b/drivers/gpu/drm/xe/xe_pxp_submit.c index f5f6b18c10548..b50fe037c74b4 100644 --- a/drivers/gpu/drm/xe/xe_pxp_submit.c +++ b/drivers/gpu/drm/xe/xe_pxp_submit.c @@ -16,6 +16,7 @@ #include "xe_gt.h" #include "xe_lrc.h" #include "xe_map.h" +#include "xe_pxp.h" #include "xe_pxp_types.h" #include "xe_sched_job.h" #include "xe_vm.h" @@ -490,6 +491,52 @@ static int gsccs_send_message(struct xe_pxp_gsc_client_resources *gsc_res, return ret; } +/** + * xe_pxp_submit_session_init - submits a PXP GSC session initialization + * @gsc_res: the pxp client resources + * @id: the session to initialize + * + * Submit a message to the GSC FW to initialize (i.e. start) a PXP session. + * + * Returns 0 if the submission is successful, an errno value otherwise. + */ +int xe_pxp_submit_session_init(struct xe_pxp_gsc_client_resources *gsc_res, u32 id) +{ + struct xe_device *xe = gsc_res->vm->xe; + struct pxp43_create_arb_in msg_in = {0}; + struct pxp43_create_arb_out msg_out = {0}; + int ret; + + msg_in.header.api_version = PXP_APIVER(4, 3); + msg_in.header.command_id = PXP43_CMDID_INIT_SESSION; + msg_in.header.stream_id = (FIELD_PREP(PXP43_INIT_SESSION_APPID, id) | + FIELD_PREP(PXP43_INIT_SESSION_VALID, 1) | + FIELD_PREP(PXP43_INIT_SESSION_APPTYPE, 0)); + msg_in.header.buffer_len = sizeof(msg_in) - sizeof(msg_in.header); + + if (id == DRM_XE_PXP_HWDRM_DEFAULT_SESSION) + msg_in.protection_mode = PXP43_INIT_SESSION_PROTECTION_ARB; + + ret = gsccs_send_message(gsc_res, &msg_in, sizeof(msg_in), + &msg_out, sizeof(msg_out)); + if (ret) { + drm_err(&xe->drm, "Failed to init PXP session %u (%pe)\n", id, ERR_PTR(ret)); + } else if (msg_out.header.status != 0) { + ret = -EIO; + + if (is_fw_err_platform_config(msg_out.header.status)) + drm_info_once(&xe->drm, + "Failed to init PXP session %u due to BIOS/SOC, s=0x%x(%s)\n", + id, msg_out.header.status, + fw_err_to_string(msg_out.header.status)); + else + drm_dbg(&xe->drm, "Failed to init PXP session %u, s=0x%x\n", + id, msg_out.header.status); + } + + return ret; +} + /** * xe_pxp_submit_session_invalidation - submits a PXP GSC invalidation * @gsc_res: the pxp client resources diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.h b/drivers/gpu/drm/xe/xe_pxp_submit.h index 48fdc9b091163..c9efda02f4b0a 100644 --- a/drivers/gpu/drm/xe/xe_pxp_submit.h +++ b/drivers/gpu/drm/xe/xe_pxp_submit.h @@ -14,6 +14,7 @@ struct xe_pxp_gsc_client_resources; int xe_pxp_allocate_execution_resources(struct xe_pxp *pxp); void xe_pxp_destroy_execution_resources(struct xe_pxp *pxp); +int xe_pxp_submit_session_init(struct xe_pxp_gsc_client_resources *gsc_res, u32 id); int xe_pxp_submit_session_termination(struct xe_pxp *pxp, u32 id); int xe_pxp_submit_session_invalidation(struct xe_pxp_gsc_client_resources *gsc_res, u32 id); From f8caa80154c4b5481476d1aad8bef335b5f90e6d Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:31 -0800 Subject: [PATCH 077/130] drm/xe/pxp: Add PXP queue tracking and session start We expect every queue that uses PXP to be marked as doing so, to allow the driver to correctly manage the encryption status. The API for doing this from userspace is coming in the next patch, while this patch implement the management side of things. When a PXP queue is created, the driver will do the following: - Start the default PXP session if it is not already running; - assign an rpm ref to the queue to keep for its lifetime (this is required because PXP HWDRM sessions are killed by the HW suspend flow). Since PXP start and termination can race each other, this patch also introduces locking and a state machine to keep track of the pending operations. Note that since we'll need to take the lock from the suspend/resume paths as well, we can't do submissions while holding it, which means we need a slightly more complicated state machine to keep track of intermediate steps. v4: new patch in the series, split from the following interface patch to keep review manageable. Lock and status rework to not do submissions under lock. v5: Improve comments and error logs (John) Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-8-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_exec_queue.c | 1 + drivers/gpu/drm/xe/xe_exec_queue_types.h | 6 + drivers/gpu/drm/xe/xe_pxp.c | 383 ++++++++++++++++++++++- drivers/gpu/drm/xe/xe_pxp.h | 5 + drivers/gpu/drm/xe/xe_pxp_types.h | 30 ++ 5 files changed, 419 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 252bfa11cae92..2ec4e2eb6f2a7 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -78,6 +78,7 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe, INIT_LIST_HEAD(&q->lr.link); INIT_LIST_HEAD(&q->multi_gt_link); INIT_LIST_HEAD(&q->hw_engine_group_link); + INIT_LIST_HEAD(&q->pxp.link); q->sched_props.timeslice_us = hwe->eclass->sched_props.timeslice_us; q->sched_props.preempt_timeout_us = diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h index 5af5419cec7a6..6d85a069947fa 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h @@ -130,6 +130,12 @@ struct xe_exec_queue { struct list_head link; } lr; + /** @pxp: PXP info tracking */ + struct { + /** @pxp.link: link into the list of PXP exec queues */ + struct list_head link; + } pxp; + /** @ops: submission backend exec queue operations */ const struct xe_exec_queue_ops *ops; diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 1452a4763ac2d..69d49e34e34d6 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -8,9 +8,13 @@ #include #include "xe_device_types.h" +#include "xe_exec_queue.h" #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" #include "xe_pm.h" #include "xe_pxp_submit.h" @@ -29,6 +33,15 @@ #define ARB_SESSION DRM_XE_PXP_HWDRM_DEFAULT_SESSION /* shorter define */ +/* + * A submission to GSC can take up to 250ms to complete, so use a 300ms + * timeout for activation where only one of those is involved. Termination + * additionally requires a submission to VCS and an interaction with KCR, so + * bump the timeout to 500ms for that. + */ +#define PXP_ACTIVATION_TIMEOUT_MS 300 +#define PXP_TERMINATION_TIMEOUT_MS 500 + bool xe_pxp_is_supported(const struct xe_device *xe) { return xe->info.has_pxp && IS_ENABLED(CONFIG_INTEL_MEI_GSC_PROXY); @@ -39,6 +52,40 @@ static bool pxp_is_enabled(const struct xe_pxp *pxp) return pxp; } +static bool pxp_prerequisites_done(const struct xe_pxp *pxp) +{ + struct xe_gt *gt = pxp->gt; + unsigned int fw_ref; + bool ready; + + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); + + /* + * If force_wake fails we could falsely report the prerequisites as not + * done even if they are; the consequence of this would be that the + * callers won't go ahead with using PXP, but if force_wake doesn't work + * the GT is very likely in a bad state so not really a problem to abort + * PXP. Therefore, we can just log the force_wake error and not escalate + * it. + */ + XE_WARN_ON(!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)); + + /* PXP requires both HuC authentication via GSC and GSC proxy initialized */ + ready = xe_huc_is_authenticated(>->uc.huc, XE_HUC_AUTH_VIA_GSC) && + xe_gsc_proxy_init_done(>->uc.gsc); + + xe_force_wake_put(gt_to_fw(gt), fw_ref); + + return ready; +} + +static bool pxp_session_is_in_play(struct xe_pxp *pxp, u32 id) +{ + struct xe_gt *gt = pxp->gt; + + return xe_mmio_read32(>->mmio, KCR_SIP) & BIT(id); +} + static int pxp_wait_for_session_state(struct xe_pxp *pxp, u32 id, bool in_play) { struct xe_gt *gt = pxp->gt; @@ -48,14 +95,15 @@ static int pxp_wait_for_session_state(struct xe_pxp *pxp, u32 id, bool in_play) 250, NULL, false); } -static void pxp_terminate(struct xe_pxp *pxp) +static void pxp_invalidate_queues(struct xe_pxp *pxp); + +static int pxp_terminate_hw(struct xe_pxp *pxp) { - int ret = 0; - struct xe_device *xe = pxp->xe; struct xe_gt *gt = pxp->gt; unsigned int fw_ref; + int ret = 0; - drm_dbg(&xe->drm, "Terminating PXP\n"); + drm_dbg(&pxp->xe->drm, "Terminating PXP\n"); fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) { @@ -80,14 +128,83 @@ static void pxp_terminate(struct xe_pxp *pxp) out: xe_force_wake_put(gt_to_fw(gt), fw_ref); + return ret; +} - if (ret) +static void mark_termination_in_progress(struct xe_pxp *pxp) +{ + lockdep_assert_held(&pxp->mutex); + + reinit_completion(&pxp->termination); + pxp->status = XE_PXP_TERMINATION_IN_PROGRESS; +} + +static void pxp_terminate(struct xe_pxp *pxp) +{ + int ret = 0; + struct xe_device *xe = pxp->xe; + + if (!wait_for_completion_timeout(&pxp->activation, + msecs_to_jiffies(PXP_ACTIVATION_TIMEOUT_MS))) + drm_err(&xe->drm, "failed to wait for PXP start before termination\n"); + + mutex_lock(&pxp->mutex); + + pxp_invalidate_queues(pxp); + + /* + * If we have a termination already in progress, we need to wait for + * it to complete before queueing another one. Once the first + * termination is completed we'll set the state back to + * NEEDS_TERMINATION and leave it to the pxp start code to issue it. + */ + if (pxp->status == XE_PXP_TERMINATION_IN_PROGRESS) { + pxp->status = XE_PXP_NEEDS_ADDITIONAL_TERMINATION; + mutex_unlock(&pxp->mutex); + return; + } + + mark_termination_in_progress(pxp); + + mutex_unlock(&pxp->mutex); + + ret = pxp_terminate_hw(pxp); + if (ret) { drm_err(&xe->drm, "PXP termination failed: %pe\n", ERR_PTR(ret)); + mutex_lock(&pxp->mutex); + pxp->status = XE_PXP_ERROR; + complete_all(&pxp->termination); + mutex_unlock(&pxp->mutex); + } } static void pxp_terminate_complete(struct xe_pxp *pxp) { - /* TODO mark the session as ready to start */ + /* + * We expect PXP to be in one of 2 states when we get here: + * - XE_PXP_TERMINATION_IN_PROGRESS: a single termination event was + * requested and it is now completing, so we're ready to start. + * - XE_PXP_NEEDS_ADDITIONAL_TERMINATION: a second termination was + * requested while the first one was still being processed. + */ + mutex_lock(&pxp->mutex); + + switch (pxp->status) { + case XE_PXP_TERMINATION_IN_PROGRESS: + pxp->status = XE_PXP_READY_TO_START; + break; + case XE_PXP_NEEDS_ADDITIONAL_TERMINATION: + pxp->status = XE_PXP_NEEDS_TERMINATION; + break; + default: + drm_err(&pxp->xe->drm, + "PXP termination complete while status was %u\n", + pxp->status); + } + + complete_all(&pxp->termination); + + mutex_unlock(&pxp->mutex); } static void pxp_irq_work(struct work_struct *work) @@ -229,10 +346,24 @@ int xe_pxp_init(struct xe_device *xe) if (!pxp) return -ENOMEM; + INIT_LIST_HEAD(&pxp->queues.list); + spin_lock_init(&pxp->queues.lock); INIT_WORK(&pxp->irq.work, pxp_irq_work); pxp->xe = xe; pxp->gt = gt; + /* + * we'll use the completions to check if there is an action pending, + * so we start them as completed and we reinit it when an action is + * triggered. + */ + init_completion(&pxp->activation); + init_completion(&pxp->termination); + complete_all(&pxp->termination); + complete_all(&pxp->activation); + + mutex_init(&pxp->mutex); + pxp->irq.wq = alloc_ordered_workqueue("pxp-wq", 0); if (!pxp->irq.wq) { err = -ENOMEM; @@ -259,3 +390,243 @@ int xe_pxp_init(struct xe_device *xe) drmm_kfree(&xe->drm, pxp); return err; } + +static int __pxp_start_arb_session(struct xe_pxp *pxp) +{ + int ret; + unsigned int fw_ref; + + fw_ref = xe_force_wake_get(gt_to_fw(pxp->gt), XE_FW_GT); + if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) + return -EIO; + + if (pxp_session_is_in_play(pxp, ARB_SESSION)) { + ret = -EEXIST; + goto out_force_wake; + } + + ret = xe_pxp_submit_session_init(&pxp->gsc_res, ARB_SESSION); + if (ret) { + drm_err(&pxp->xe->drm, "Failed to init PXP arb session: %pe\n", ERR_PTR(ret)); + goto out_force_wake; + } + + ret = pxp_wait_for_session_state(pxp, ARB_SESSION, true); + if (ret) { + drm_err(&pxp->xe->drm, "PXP ARB session failed to go in play%pe\n", ERR_PTR(ret)); + goto out_force_wake; + } + + drm_dbg(&pxp->xe->drm, "PXP ARB session is active\n"); + +out_force_wake: + xe_force_wake_put(gt_to_fw(pxp->gt), fw_ref); + return ret; +} + +static void __exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q) +{ + spin_lock_irq(&pxp->queues.lock); + list_add_tail(&q->pxp.link, &pxp->queues.list); + spin_unlock_irq(&pxp->queues.lock); +} + +/** + * xe_pxp_exec_queue_add - add a queue to the PXP list + * @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled) + * @q: the queue to add to the list + * + * If PXP is enabled and the prerequisites are done, start the PXP ARB + * session (if not already running) and add the queue to the PXP list. Note + * that the queue must have previously been marked as using PXP with + * xe_pxp_exec_queue_set_type. + * + * Returns 0 if the PXP ARB session is running and the queue is in the list, + * -ENODEV if PXP is disabled, -EBUSY if the PXP prerequisites are not done, + * other errno value if something goes wrong during the session start. + */ +int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q) +{ + int ret = 0; + + if (!pxp_is_enabled(pxp)) + return -ENODEV; + + /* + * Runtime suspend kills PXP, so we take a reference to prevent it from + * happening while we have active queues that use PXP + */ + xe_pm_runtime_get(pxp->xe); + + if (!pxp_prerequisites_done(pxp)) { + ret = -EBUSY; + goto out; + } + +wait_for_idle: + /* + * if there is an action in progress, wait for it. We need to wait + * outside the lock because the completion is done from within the lock. + * Note that the two action should never be pending at the same time. + */ + if (!wait_for_completion_timeout(&pxp->termination, + msecs_to_jiffies(PXP_TERMINATION_TIMEOUT_MS))) { + ret = -ETIMEDOUT; + goto out; + } + + if (!wait_for_completion_timeout(&pxp->activation, + msecs_to_jiffies(PXP_ACTIVATION_TIMEOUT_MS))) { + ret = -ETIMEDOUT; + goto out; + } + + mutex_lock(&pxp->mutex); + + /* If PXP is not already active, turn it on */ + switch (pxp->status) { + case XE_PXP_ERROR: + ret = -EIO; + break; + case XE_PXP_ACTIVE: + __exec_queue_add(pxp, q); + mutex_unlock(&pxp->mutex); + goto out; + case XE_PXP_READY_TO_START: + pxp->status = XE_PXP_START_IN_PROGRESS; + reinit_completion(&pxp->activation); + break; + case XE_PXP_START_IN_PROGRESS: + /* If a start is in progress then the completion must not be done */ + XE_WARN_ON(completion_done(&pxp->activation)); + mutex_unlock(&pxp->mutex); + goto wait_for_idle; + case XE_PXP_NEEDS_TERMINATION: + mark_termination_in_progress(pxp); + break; + case XE_PXP_TERMINATION_IN_PROGRESS: + case XE_PXP_NEEDS_ADDITIONAL_TERMINATION: + /* If a termination is in progress then the completion must not be done */ + XE_WARN_ON(completion_done(&pxp->termination)); + mutex_unlock(&pxp->mutex); + goto wait_for_idle; + default: + drm_err(&pxp->xe->drm, "unexpected state during PXP start: %u\n", pxp->status); + ret = -EIO; + break; + } + + mutex_unlock(&pxp->mutex); + + if (ret) + goto out; + + if (!completion_done(&pxp->termination)) { + ret = pxp_terminate_hw(pxp); + if (ret) { + drm_err(&pxp->xe->drm, "PXP termination failed before start\n"); + mutex_lock(&pxp->mutex); + pxp->status = XE_PXP_ERROR; + mutex_unlock(&pxp->mutex); + + goto out; + } + + goto wait_for_idle; + } + + /* All the cases except for start should have exited earlier */ + XE_WARN_ON(completion_done(&pxp->activation)); + ret = __pxp_start_arb_session(pxp); + + mutex_lock(&pxp->mutex); + + complete_all(&pxp->activation); + + /* + * Any other process should wait until the state goes away from + * XE_PXP_START_IN_PROGRESS, so if the state is not that something went + * wrong. Mark the status as needing termination and try again. + */ + if (pxp->status != XE_PXP_START_IN_PROGRESS) { + drm_err(&pxp->xe->drm, "unexpected state after PXP start: %u\n", pxp->status); + pxp->status = XE_PXP_NEEDS_TERMINATION; + mutex_unlock(&pxp->mutex); + goto wait_for_idle; + } + + /* If everything went ok, update the status and add the queue to the list */ + if (!ret) { + pxp->status = XE_PXP_ACTIVE; + __exec_queue_add(pxp, q); + } else { + pxp->status = XE_PXP_ERROR; + } + + mutex_unlock(&pxp->mutex); + +out: + /* + * in the successful case the PM ref is released from + * xe_pxp_exec_queue_remove + */ + if (ret) + xe_pm_runtime_put(pxp->xe); + + return ret; +} + +/** + * xe_pxp_exec_queue_remove - remove a queue from the PXP list + * @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled) + * @q: the queue to remove from the list + * + * If PXP is enabled and the exec_queue is in the list, the queue will be + * removed from the list and its PM reference will be released. It is safe to + * call this function multiple times for the same queue. + */ +void xe_pxp_exec_queue_remove(struct xe_pxp *pxp, struct xe_exec_queue *q) +{ + bool need_pm_put = false; + + if (!pxp_is_enabled(pxp)) + return; + + spin_lock_irq(&pxp->queues.lock); + + if (!list_empty(&q->pxp.link)) { + list_del_init(&q->pxp.link); + need_pm_put = true; + } + + spin_unlock_irq(&pxp->queues.lock); + + if (need_pm_put) + xe_pm_runtime_put(pxp->xe); +} + +static void pxp_invalidate_queues(struct xe_pxp *pxp) +{ + struct xe_exec_queue *tmp, *q; + + spin_lock_irq(&pxp->queues.lock); + + /* + * Removing a queue from the PXP list requires a put of the RPM ref that + * the queue holds to keep the PXP session alive, which can't be done + * under spinlock. Since it is safe to kill a queue multiple times, we + * can leave the invalid queue in the list for now and postpone the + * removal and associated RPM put to when the queue is destroyed. + */ + list_for_each_entry(tmp, &pxp->queues.list, pxp.link) { + q = xe_exec_queue_get_unless_zero(tmp); + + if (!q) + continue; + + xe_exec_queue_kill(q); + xe_exec_queue_put(q); + } + + spin_unlock_irq(&pxp->queues.lock); +} diff --git a/drivers/gpu/drm/xe/xe_pxp.h b/drivers/gpu/drm/xe/xe_pxp.h index 39435c644dcda..f482567c27b58 100644 --- a/drivers/gpu/drm/xe/xe_pxp.h +++ b/drivers/gpu/drm/xe/xe_pxp.h @@ -9,6 +9,8 @@ #include struct xe_device; +struct xe_exec_queue; +struct xe_pxp; #define DRM_XE_PXP_HWDRM_DEFAULT_SESSION 0xF /* TODO: move to uapi */ @@ -17,4 +19,7 @@ bool xe_pxp_is_supported(const struct xe_device *xe); int xe_pxp_init(struct xe_device *xe); void xe_pxp_irq_handler(struct xe_device *xe, u16 iir); +int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q); +void xe_pxp_exec_queue_remove(struct xe_pxp *pxp, struct xe_exec_queue *q); + #endif /* __XE_PXP_H__ */ diff --git a/drivers/gpu/drm/xe/xe_pxp_types.h b/drivers/gpu/drm/xe/xe_pxp_types.h index 311d08111b5fa..bd741720f67d2 100644 --- a/drivers/gpu/drm/xe/xe_pxp_types.h +++ b/drivers/gpu/drm/xe/xe_pxp_types.h @@ -6,7 +6,10 @@ #ifndef __XE_PXP_TYPES_H__ #define __XE_PXP_TYPES_H__ +#include #include +#include +#include #include #include @@ -16,6 +19,16 @@ struct xe_device; struct xe_gt; struct xe_vm; +enum xe_pxp_status { + XE_PXP_ERROR = -1, + XE_PXP_NEEDS_TERMINATION = 0, /* starting status */ + XE_PXP_NEEDS_ADDITIONAL_TERMINATION, + XE_PXP_TERMINATION_IN_PROGRESS, + XE_PXP_READY_TO_START, + XE_PXP_START_IN_PROGRESS, + XE_PXP_ACTIVE, +}; + /** * struct xe_pxp_gsc_client_resources - resources for GSC submission by a PXP * client. The GSC FW supports multiple GSC client active at the same time. @@ -82,6 +95,23 @@ struct xe_pxp { #define PXP_TERMINATION_REQUEST BIT(0) #define PXP_TERMINATION_COMPLETE BIT(1) } irq; + + /** @mutex: protects the pxp status and the queue list */ + struct mutex mutex; + /** @status: the current pxp status */ + enum xe_pxp_status status; + /** @activation: completion struct that tracks pxp start */ + struct completion activation; + /** @termination: completion struct that tracks terminations */ + struct completion termination; + + /** @queues: management of exec_queues that use PXP */ + struct { + /** @queues.lock: spinlock protecting the queue management */ + spinlock_t lock; + /** @queues.list: list of exec_queues that use PXP */ + struct list_head list; + } queues; }; #endif /* __XE_PXP_TYPES_H__ */ From 72d479601d67026c4fafaad21762a777cf41f906 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:32 -0800 Subject: [PATCH 078/130] drm/xe/pxp/uapi: Add userspace and LRC support for PXP-using queues Userspace is required to mark a queue as using PXP to guarantee that the PXP instructions will work. In addition to managing the PXP sessions, when a PXP queue is created the driver will set the relevant bits in its context control register. On submission of a valid PXP queue, the driver will validate all encrypted objects mapped to the VM to ensured they were encrypted with the current key. v2: Remove pxp_types include outside of PXP code (Jani), better comments and code cleanup (John) v3: split the internal PXP management to a separate patch for ease of review. re-order ioctl checks to always return -EINVAL if parameters are invalid, rebase on msix changes. Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-9-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/regs/xe_engine_regs.h | 1 + drivers/gpu/drm/xe/xe_exec_queue.c | 56 +++++++++++++++++++++++- drivers/gpu/drm/xe/xe_exec_queue.h | 5 +++ drivers/gpu/drm/xe/xe_exec_queue_types.h | 2 + drivers/gpu/drm/xe/xe_execlist.c | 2 +- drivers/gpu/drm/xe/xe_lrc.c | 18 ++++++-- drivers/gpu/drm/xe/xe_lrc.h | 4 +- drivers/gpu/drm/xe/xe_pxp.c | 35 +++++++++++++-- drivers/gpu/drm/xe/xe_pxp.h | 4 +- include/uapi/drm/xe_drm.h | 40 ++++++++++++++++- 10 files changed, 153 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_engine_regs.h b/drivers/gpu/drm/xe/regs/xe_engine_regs.h index d86219dedde2a..c8fd3d5ca5026 100644 --- a/drivers/gpu/drm/xe/regs/xe_engine_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_engine_regs.h @@ -132,6 +132,7 @@ #define RING_EXECLIST_STATUS_HI(base) XE_REG((base) + 0x234 + 4) #define RING_CONTEXT_CONTROL(base) XE_REG((base) + 0x244, XE_REG_OPTION_MASKED) +#define CTX_CTRL_PXP_ENABLE REG_BIT(10) #define CTX_CTRL_OAC_CONTEXT_ENABLE REG_BIT(8) #define CTX_CTRL_RUN_ALONE REG_BIT(7) #define CTX_CTRL_INDIRECT_RING_STATE_ENABLE REG_BIT(4) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 2ec4e2eb6f2a7..6051db78d7065 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -25,6 +25,7 @@ #include "xe_ring_ops_types.h" #include "xe_trace.h" #include "xe_vm.h" +#include "xe_pxp.h" enum xe_exec_queue_sched_prop { XE_EXEC_QUEUE_JOB_TIMEOUT = 0, @@ -38,6 +39,8 @@ static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue static void __xe_exec_queue_free(struct xe_exec_queue *q) { + if (xe_exec_queue_uses_pxp(q)) + xe_pxp_exec_queue_remove(gt_to_xe(q->gt)->pxp, q); if (q->vm) xe_vm_put(q->vm); @@ -113,6 +116,21 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q) { struct xe_vm *vm = q->vm; int i, err; + u32 flags = 0; + + /* + * PXP workloads executing on RCS or CCS must run in isolation (i.e. no + * other workload can use the EUs at the same time). On MTL this is done + * by setting the RUNALONE bit in the LRC, while starting on Xe2 there + * is a dedicated bit for it. + */ + if (xe_exec_queue_uses_pxp(q) && + (q->class == XE_ENGINE_CLASS_RENDER || q->class == XE_ENGINE_CLASS_COMPUTE)) { + if (GRAPHICS_VER(gt_to_xe(q->gt)) >= 20) + flags |= XE_LRC_CREATE_PXP; + else + flags |= XE_LRC_CREATE_RUNALONE; + } if (vm) { err = xe_vm_lock(vm, true); @@ -121,7 +139,7 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q) } for (i = 0; i < q->width; ++i) { - q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K, q->msix_vec); + q->lrc[i] = xe_lrc_create(q->hwe, q->vm, SZ_16K, q->msix_vec, flags); if (IS_ERR(q->lrc[i])) { err = PTR_ERR(q->lrc[i]); goto err_unlock; @@ -166,6 +184,19 @@ struct xe_exec_queue *xe_exec_queue_create(struct xe_device *xe, struct xe_vm *v if (err) goto err_post_alloc; + /* + * We can only add the queue to the PXP list after the init is complete, + * because the PXP termination can call exec_queue_kill and that will + * go bad if the queue is only half-initialized. This means that we + * can't do it when we handle the PXP extension in __xe_exec_queue_alloc + * and we need to do it here instead. + */ + if (xe_exec_queue_uses_pxp(q)) { + err = xe_pxp_exec_queue_add(xe->pxp, q); + if (err) + goto err_post_alloc; + } + return q; err_post_alloc: @@ -254,6 +285,9 @@ void xe_exec_queue_destroy(struct kref *ref) struct xe_exec_queue *q = container_of(ref, struct xe_exec_queue, refcount); struct xe_exec_queue *eq, *next; + if (xe_exec_queue_uses_pxp(q)) + xe_pxp_exec_queue_remove(gt_to_xe(q->gt)->pxp, q); + xe_exec_queue_last_fence_put_unlocked(q); if (!(q->flags & EXEC_QUEUE_FLAG_BIND_ENGINE_CHILD)) { list_for_each_entry_safe(eq, next, &q->multi_gt_list, @@ -409,6 +443,22 @@ static int exec_queue_set_timeslice(struct xe_device *xe, struct xe_exec_queue * return 0; } +static int +exec_queue_set_pxp_type(struct xe_device *xe, struct xe_exec_queue *q, u64 value) +{ + if (value == DRM_XE_PXP_TYPE_NONE) + return 0; + + /* we only support HWDRM sessions right now */ + if (XE_IOCTL_DBG(xe, value != DRM_XE_PXP_TYPE_HWDRM)) + return -EINVAL; + + if (!xe_pxp_is_enabled(xe->pxp)) + return -ENODEV; + + return xe_pxp_exec_queue_set_type(xe->pxp, q, DRM_XE_PXP_TYPE_HWDRM); +} + typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe, struct xe_exec_queue *q, u64 value); @@ -416,6 +466,7 @@ typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe, static const xe_exec_queue_set_property_fn exec_queue_set_property_funcs[] = { [DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY] = exec_queue_set_priority, [DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE] = exec_queue_set_timeslice, + [DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE] = exec_queue_set_pxp_type, }; static int exec_queue_user_ext_set_property(struct xe_device *xe, @@ -435,7 +486,8 @@ static int exec_queue_user_ext_set_property(struct xe_device *xe, ARRAY_SIZE(exec_queue_set_property_funcs)) || XE_IOCTL_DBG(xe, ext.pad) || XE_IOCTL_DBG(xe, ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY && - ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE)) + ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE && + ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE)) return -EINVAL; idx = array_index_nospec(ext.property, ARRAY_SIZE(exec_queue_set_property_funcs)); diff --git a/drivers/gpu/drm/xe/xe_exec_queue.h b/drivers/gpu/drm/xe/xe_exec_queue.h index 90c7f73eab884..17bc50a7f05a4 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.h +++ b/drivers/gpu/drm/xe/xe_exec_queue.h @@ -57,6 +57,11 @@ static inline bool xe_exec_queue_is_parallel(struct xe_exec_queue *q) return q->width > 1; } +static inline bool xe_exec_queue_uses_pxp(struct xe_exec_queue *q) +{ + return q->pxp.type; +} + bool xe_exec_queue_is_lr(struct xe_exec_queue *q); bool xe_exec_queue_ring_full(struct xe_exec_queue *q); diff --git a/drivers/gpu/drm/xe/xe_exec_queue_types.h b/drivers/gpu/drm/xe/xe_exec_queue_types.h index 6d85a069947fa..6eb7ff091534f 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue_types.h +++ b/drivers/gpu/drm/xe/xe_exec_queue_types.h @@ -132,6 +132,8 @@ struct xe_exec_queue { /** @pxp: PXP info tracking */ struct { + /** @pxp.type: PXP session type used by this queue */ + u8 type; /** @pxp.link: link into the list of PXP exec queues */ struct list_head link; } pxp; diff --git a/drivers/gpu/drm/xe/xe_execlist.c b/drivers/gpu/drm/xe/xe_execlist.c index 5ef96deaa8811..779a52daf3d7e 100644 --- a/drivers/gpu/drm/xe/xe_execlist.c +++ b/drivers/gpu/drm/xe/xe_execlist.c @@ -269,7 +269,7 @@ struct xe_execlist_port *xe_execlist_port_create(struct xe_device *xe, port->hwe = hwe; - port->lrc = xe_lrc_create(hwe, NULL, SZ_16K, XE_IRQ_DEFAULT_MSIX); + port->lrc = xe_lrc_create(hwe, NULL, SZ_16K, XE_IRQ_DEFAULT_MSIX, 0); if (IS_ERR(port->lrc)) { err = PTR_ERR(port->lrc); goto err; diff --git a/drivers/gpu/drm/xe/xe_lrc.c b/drivers/gpu/drm/xe/xe_lrc.c index bbb9ffbf63672..df3ceddede070 100644 --- a/drivers/gpu/drm/xe/xe_lrc.c +++ b/drivers/gpu/drm/xe/xe_lrc.c @@ -883,7 +883,8 @@ static void xe_lrc_finish(struct xe_lrc *lrc) #define PVC_CTX_ACC_CTR_THOLD (0x2a + 1) static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, - struct xe_vm *vm, u32 ring_size, u16 msix_vec) + struct xe_vm *vm, u32 ring_size, u16 msix_vec, + u32 init_flags) { struct xe_gt *gt = hwe->gt; struct xe_tile *tile = gt_to_tile(gt); @@ -979,6 +980,16 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, RING_CTL_SIZE(lrc->ring.size) | RING_VALID); } + if (init_flags & XE_LRC_CREATE_RUNALONE) + xe_lrc_write_ctx_reg(lrc, CTX_CONTEXT_CONTROL, + xe_lrc_read_ctx_reg(lrc, CTX_CONTEXT_CONTROL) | + _MASKED_BIT_ENABLE(CTX_CTRL_RUN_ALONE)); + + if (init_flags & XE_LRC_CREATE_PXP) + xe_lrc_write_ctx_reg(lrc, CTX_CONTEXT_CONTROL, + xe_lrc_read_ctx_reg(lrc, CTX_CONTEXT_CONTROL) | + _MASKED_BIT_ENABLE(CTX_CTRL_PXP_ENABLE)); + xe_lrc_write_ctx_reg(lrc, CTX_TIMESTAMP, 0); if (xe->info.has_asid && vm) @@ -1021,6 +1032,7 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, * @vm: The VM (address space) * @ring_size: LRC ring size * @msix_vec: MSI-X interrupt vector (for platforms that support it) + * @flags: LRC initialization flags * * Allocate and initialize the Logical Ring Context (LRC). * @@ -1028,7 +1040,7 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, * upon failure. */ struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, - u32 ring_size, u16 msix_vec) + u32 ring_size, u16 msix_vec, u32 flags) { struct xe_lrc *lrc; int err; @@ -1037,7 +1049,7 @@ struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, if (!lrc) return ERR_PTR(-ENOMEM); - err = xe_lrc_init(lrc, hwe, vm, ring_size, msix_vec); + err = xe_lrc_init(lrc, hwe, vm, ring_size, msix_vec, flags); if (err) { kfree(lrc); return ERR_PTR(err); diff --git a/drivers/gpu/drm/xe/xe_lrc.h b/drivers/gpu/drm/xe/xe_lrc.h index b27e80cd842ac..0b40f349ab95d 100644 --- a/drivers/gpu/drm/xe/xe_lrc.h +++ b/drivers/gpu/drm/xe/xe_lrc.h @@ -42,8 +42,10 @@ struct xe_lrc_snapshot { #define LRC_PPHWSP_FLUSH_INVAL_SCRATCH_ADDR (0x34 * 4) #define LRC_PPHWSP_PXP_INVAL_SCRATCH_ADDR (0x40 * 4) +#define XE_LRC_CREATE_RUNALONE 0x1 +#define XE_LRC_CREATE_PXP 0x2 struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, - u32 ring_size, u16 msix_vec); + u32 ring_size, u16 msix_vec, u32 flags); void xe_lrc_destroy(struct kref *ref); /** diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 69d49e34e34d6..b32121273e0de 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -6,6 +6,7 @@ #include "xe_pxp.h" #include +#include #include "xe_device_types.h" #include "xe_exec_queue.h" @@ -47,7 +48,7 @@ bool xe_pxp_is_supported(const struct xe_device *xe) return xe->info.has_pxp && IS_ENABLED(CONFIG_INTEL_MEI_GSC_PROXY); } -static bool pxp_is_enabled(const struct xe_pxp *pxp) +bool xe_pxp_is_enabled(const struct xe_pxp *pxp) { return pxp; } @@ -249,7 +250,7 @@ void xe_pxp_irq_handler(struct xe_device *xe, u16 iir) { struct xe_pxp *pxp = xe->pxp; - if (!pxp_is_enabled(pxp)) { + if (!xe_pxp_is_enabled(pxp)) { drm_err(&xe->drm, "PXP irq 0x%x received with PXP disabled!\n", iir); return; } @@ -424,6 +425,27 @@ static int __pxp_start_arb_session(struct xe_pxp *pxp) return ret; } +/** + * xe_pxp_exec_queue_set_type - Mark a queue as using PXP + * @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled) + * @q: the queue to mark as using PXP + * @type: the type of PXP session this queue will use + * + * Returns 0 if the selected PXP type is supported, -ENODEV otherwise. + */ +int xe_pxp_exec_queue_set_type(struct xe_pxp *pxp, struct xe_exec_queue *q, u8 type) +{ + if (!xe_pxp_is_enabled(pxp)) + return -ENODEV; + + /* we only support HWDRM sessions right now */ + xe_assert(pxp->xe, type == DRM_XE_PXP_TYPE_HWDRM); + + q->pxp.type = type; + + return 0; +} + static void __exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q) { spin_lock_irq(&pxp->queues.lock); @@ -449,9 +471,12 @@ int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q) { int ret = 0; - if (!pxp_is_enabled(pxp)) + if (!xe_pxp_is_enabled(pxp)) return -ENODEV; + /* we only support HWDRM sessions right now */ + xe_assert(pxp->xe, q->pxp.type == DRM_XE_PXP_TYPE_HWDRM); + /* * Runtime suspend kills PXP, so we take a reference to prevent it from * happening while we have active queues that use PXP @@ -589,7 +614,7 @@ void xe_pxp_exec_queue_remove(struct xe_pxp *pxp, struct xe_exec_queue *q) { bool need_pm_put = false; - if (!pxp_is_enabled(pxp)) + if (!xe_pxp_is_enabled(pxp)) return; spin_lock_irq(&pxp->queues.lock); @@ -599,6 +624,8 @@ void xe_pxp_exec_queue_remove(struct xe_pxp *pxp, struct xe_exec_queue *q) need_pm_put = true; } + q->pxp.type = DRM_XE_PXP_TYPE_NONE; + spin_unlock_irq(&pxp->queues.lock); if (need_pm_put) diff --git a/drivers/gpu/drm/xe/xe_pxp.h b/drivers/gpu/drm/xe/xe_pxp.h index f482567c27b58..2e0ab186072a1 100644 --- a/drivers/gpu/drm/xe/xe_pxp.h +++ b/drivers/gpu/drm/xe/xe_pxp.h @@ -12,13 +12,13 @@ struct xe_device; struct xe_exec_queue; struct xe_pxp; -#define DRM_XE_PXP_HWDRM_DEFAULT_SESSION 0xF /* TODO: move to uapi */ - bool xe_pxp_is_supported(const struct xe_device *xe); +bool xe_pxp_is_enabled(const struct xe_pxp *pxp); int xe_pxp_init(struct xe_device *xe); void xe_pxp_irq_handler(struct xe_device *xe, u16 iir); +int xe_pxp_exec_queue_set_type(struct xe_pxp *pxp, struct xe_exec_queue *q, u8 type); int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q); void xe_pxp_exec_queue_remove(struct xe_pxp *pxp, struct xe_exec_queue *q); diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index e2160330ad01f..9d53834c4c0a5 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -1114,6 +1114,24 @@ struct drm_xe_vm_bind { /** * struct drm_xe_exec_queue_create - Input of &DRM_IOCTL_XE_EXEC_QUEUE_CREATE * + * This ioctl supports setting the following properties via the + * %DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY extension, which uses the + * generic @drm_xe_ext_set_property struct: + * + * - %DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY - set the queue priority. + * CAP_SYS_NICE is required to set a value above normal. + * - %DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE - set the queue timeslice + * duration in microseconds. + * - %DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE - set the type of PXP session + * this queue will be used with. Valid values are listed in enum + * drm_xe_pxp_session_type. %DRM_XE_PXP_TYPE_NONE is the default behavior, so + * there is no need to explicitly set that. When a queue of type + * %DRM_XE_PXP_TYPE_HWDRM is created, the PXP default HWDRM session + * (%XE_PXP_HWDRM_DEFAULT_SESSION) will be started, if isn't already running. + * Given that going into a power-saving state kills PXP HWDRM sessions, + * runtime PM will be blocked while queues of this type are alive. + * All PXP queues will be killed if a PXP invalidation event occurs. + * * The example below shows how to use @drm_xe_exec_queue_create to create * a simple exec_queue (no parallel submission) of class * &DRM_XE_ENGINE_CLASS_RENDER. @@ -1137,7 +1155,7 @@ struct drm_xe_exec_queue_create { #define DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY 0 #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY 0 #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE 1 - +#define DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE 2 /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; @@ -1756,6 +1774,26 @@ struct drm_xe_oa_stream_info { __u64 reserved[3]; }; +/** + * enum drm_xe_pxp_session_type - Supported PXP session types. + * + * We currently only support HWDRM sessions, which are used for protected + * content that ends up being displayed, but the HW supports multiple types, so + * we might extend support in the future. + */ +enum drm_xe_pxp_session_type { + /** @DRM_XE_PXP_TYPE_NONE: PXP not used */ + DRM_XE_PXP_TYPE_NONE = 0, + /** + * @DRM_XE_PXP_TYPE_HWDRM: HWDRM sessions are used for content that ends + * up on the display. + */ + DRM_XE_PXP_TYPE_HWDRM = 1, +}; + +/* ID of the protected content session managed by Xe when PXP is active */ +#define DRM_XE_PXP_HWDRM_DEFAULT_SESSION 0xf + #if defined(__cplusplus) } #endif From bd98ac2e05855ea781c9b7ad30b5e1a234aefe95 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:33 -0800 Subject: [PATCH 079/130] drm/xe/pxp/uapi: Add a query for PXP status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PXP prerequisites (SW proxy and HuC auth via GSC) are completed asynchronously from driver load, which means that userspace can start submitting before we're ready to start a PXP session. Therefore, we need a query that userspace can use to check not only if PXP is supported but also to wait until the prerequisites are done. v2: Improve doc, do not report TYPE_NONE as supported (José) v3: Better comments, remove unneeded copy_from_user (John) Signed-off-by: Daniele Ceraolo Spurio Cc: José Roberto de Souza Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-10-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pxp.c | 32 ++++++++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_pxp.h | 1 + drivers/gpu/drm/xe/xe_query.c | 29 +++++++++++++++++++++++++++++ include/uapi/drm/xe_drm.h | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 97 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index b32121273e0de..24aef5c0f04a3 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -80,6 +80,38 @@ static bool pxp_prerequisites_done(const struct xe_pxp *pxp) return ready; } +/** + * xe_pxp_get_readiness_status - check whether PXP is ready for userspace use + * @pxp: the xe_pxp pointer (can be NULL if PXP is disabled) + * + * Returns: 0 if PXP is not ready yet, 1 if it is ready, a negative errno value + * if PXP is not supported/enabled or if something went wrong in the + * initialization of the prerequisites. Note that the return values of this + * function follow the uapi (see drm_xe_query_pxp_status), so they can be used + * directly in the query ioctl. + */ +int xe_pxp_get_readiness_status(struct xe_pxp *pxp) +{ + int ret = 0; + + if (!xe_pxp_is_enabled(pxp)) + return -ENODEV; + + /* if the GSC or HuC FW are in an error state, PXP will never work */ + if (xe_uc_fw_status_to_error(pxp->gt->uc.huc.fw.status) || + xe_uc_fw_status_to_error(pxp->gt->uc.gsc.fw.status)) + return -EIO; + + xe_pm_runtime_get(pxp->xe); + + /* PXP requires both HuC loaded and GSC proxy initialized */ + if (pxp_prerequisites_done(pxp)) + ret = 1; + + xe_pm_runtime_put(pxp->xe); + return ret; +} + static bool pxp_session_is_in_play(struct xe_pxp *pxp, u32 id) { struct xe_gt *gt = pxp->gt; diff --git a/drivers/gpu/drm/xe/xe_pxp.h b/drivers/gpu/drm/xe/xe_pxp.h index 2e0ab186072a1..868813cc84b9e 100644 --- a/drivers/gpu/drm/xe/xe_pxp.h +++ b/drivers/gpu/drm/xe/xe_pxp.h @@ -14,6 +14,7 @@ struct xe_pxp; bool xe_pxp_is_supported(const struct xe_device *xe); bool xe_pxp_is_enabled(const struct xe_pxp *pxp); +int xe_pxp_get_readiness_status(struct xe_pxp *pxp); int xe_pxp_init(struct xe_device *xe); void xe_pxp_irq_handler(struct xe_device *xe, u16 iir); diff --git a/drivers/gpu/drm/xe/xe_query.c b/drivers/gpu/drm/xe/xe_query.c index c059639613f7b..042f87a688e75 100644 --- a/drivers/gpu/drm/xe/xe_query.c +++ b/drivers/gpu/drm/xe/xe_query.c @@ -24,6 +24,7 @@ #include "xe_macros.h" #include "xe_mmio.h" #include "xe_oa.h" +#include "xe_pxp.h" #include "xe_ttm_vram_mgr.h" #include "xe_wa.h" @@ -698,6 +699,33 @@ static int query_oa_units(struct xe_device *xe, return ret ? -EFAULT : 0; } +static int query_pxp_status(struct xe_device *xe, struct drm_xe_device_query *query) +{ + struct drm_xe_query_pxp_status __user *query_ptr = u64_to_user_ptr(query->data); + size_t size = sizeof(struct drm_xe_query_pxp_status); + struct drm_xe_query_pxp_status resp = { 0 }; + int ret; + + if (query->size == 0) { + query->size = size; + return 0; + } else if (XE_IOCTL_DBG(xe, query->size != size)) { + return -EINVAL; + } + + ret = xe_pxp_get_readiness_status(xe->pxp); + if (ret < 0) + return ret; + + resp.status = ret; + resp.supported_session_types = BIT(DRM_XE_PXP_TYPE_HWDRM); + + if (copy_to_user(query_ptr, &resp, size)) + return -EFAULT; + + return 0; +} + static int (* const xe_query_funcs[])(struct xe_device *xe, struct drm_xe_device_query *query) = { query_engines, @@ -709,6 +737,7 @@ static int (* const xe_query_funcs[])(struct xe_device *xe, query_engine_cycles, query_uc_fw_version, query_oa_units, + query_pxp_status, }; int xe_query_ioctl(struct drm_device *dev, void *data, struct drm_file *file) diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 9d53834c4c0a5..112fd27f3c755 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -629,6 +629,39 @@ struct drm_xe_query_uc_fw_version { __u64 reserved; }; +/** + * struct drm_xe_query_pxp_status - query if PXP is ready + * + * If PXP is enabled and no fatal error has occurred, the status will be set to + * one of the following values: + * 0: PXP init still in progress + * 1: PXP init complete + * + * If PXP is not enabled or something has gone wrong, the query will be failed + * with one of the following error codes: + * -ENODEV: PXP not supported or disabled; + * -EIO: fatal error occurred during init, so PXP will never be enabled; + * -EINVAL: incorrect value provided as part of the query; + * -EFAULT: error copying the memory between kernel and userspace. + * + * The status can only be 0 in the first few seconds after driver load. If + * everything works as expected, the status will transition to init complete in + * less than 1 second, while in case of errors the driver might take longer to + * start returning an error code, but it should still take less than 10 seconds. + * + * The supported session type bitmask is based on the values in + * enum drm_xe_pxp_session_type. TYPE_NONE is always supported and therefore + * is not reported in the bitmask. + * + */ +struct drm_xe_query_pxp_status { + /** @status: current PXP status */ + __u32 status; + + /** @supported_session_types: bitmask of supported PXP session types */ + __u32 supported_session_types; +}; + /** * struct drm_xe_device_query - Input of &DRM_IOCTL_XE_DEVICE_QUERY - main * structure to query device information @@ -648,6 +681,7 @@ struct drm_xe_query_uc_fw_version { * attributes. * - %DRM_XE_DEVICE_QUERY_GT_TOPOLOGY * - %DRM_XE_DEVICE_QUERY_ENGINE_CYCLES + * - %DRM_XE_DEVICE_QUERY_PXP_STATUS * * If size is set to 0, the driver fills it with the required size for * the requested type of data to query. If size is equal to the required @@ -700,6 +734,7 @@ struct drm_xe_device_query { #define DRM_XE_DEVICE_QUERY_ENGINE_CYCLES 6 #define DRM_XE_DEVICE_QUERY_UC_FW_VERSION 7 #define DRM_XE_DEVICE_QUERY_OA_UNITS 8 +#define DRM_XE_DEVICE_QUERY_PXP_STATUS 9 /** @query: The type of data to query */ __u32 query; From 41a97c4a12947c2786a1680d6839bb72d1c57cec Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:34 -0800 Subject: [PATCH 080/130] drm/xe/pxp/uapi: Add API to mark a BO as using PXP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The driver needs to know if a BO is encrypted with PXP to enable the display decryption at flip time. Furthermore, we want to keep track of the status of the encryption and reject any operation that involves a BO that is encrypted using an old key. There are two points in time where such checks can kick in: 1 - at VM bind time, all operations except for unmapping will be rejected if the key used to encrypt the BO is no longer valid. This check is opt-in via a new VM_BIND flag, to avoid a scenario where a malicious app purposely shares an invalid BO with a non-PXP aware app (such as a compositor). If the VM_BIND was failed, the compositor would be unable to display anything at all. Allowing the bind to go through means that output still works, it just displays garbage data within the bounds of the illegal BO. 2 - at job submission time, if the queue is marked as using PXP, all objects bound to the VM will be checked and the submission will be rejected if any of them was encrypted with a key that is no longer valid. Note that there is no risk of leaking the encrypted data if a user does not opt-in to those checks; the only consequence is that the user will not realize that the encryption key is changed and that the data is no longer valid. v2: Better commnnts and descriptions (John), rebase v3: Properly return the result of key_assign up the stack, do not use xe_bo in display headers (Jani) v4: improve key_instance variable documentation (John) Signed-off-by: Daniele Ceraolo Spurio Cc: Matthew Brost Cc: Thomas Hellström Cc: John Harrison Cc: Jani Nikula Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-11-daniele.ceraolospurio@intel.com --- .../xe/compat-i915-headers/pxp/intel_pxp.h | 12 ++- drivers/gpu/drm/xe/display/intel_bo.c | 2 +- drivers/gpu/drm/xe/xe_bo.c | 98 ++++++++++++++++++- drivers/gpu/drm/xe/xe_bo.h | 5 + drivers/gpu/drm/xe/xe_bo_types.h | 6 ++ drivers/gpu/drm/xe/xe_exec.c | 6 ++ drivers/gpu/drm/xe/xe_pxp.c | 90 +++++++++++++++++ drivers/gpu/drm/xe/xe_pxp.h | 6 ++ drivers/gpu/drm/xe/xe_pxp_types.h | 11 +++ drivers/gpu/drm/xe/xe_vm.c | 46 ++++++++- drivers/gpu/drm/xe/xe_vm.h | 2 + include/uapi/drm/xe_drm.h | 19 ++++ 12 files changed, 296 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h b/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h index 419e8e926f00f..d2eb8e1f6c4b4 100644 --- a/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h +++ b/drivers/gpu/drm/xe/compat-i915-headers/pxp/intel_pxp.h @@ -9,6 +9,8 @@ #include #include +#include "xe_pxp.h" + struct drm_gem_object; struct xe_pxp; @@ -16,7 +18,15 @@ static inline int intel_pxp_key_check(struct xe_pxp *pxp, struct drm_gem_object *obj, bool assign) { - return -ENODEV; + /* + * The assign variable is used in i915 to assign the key to the BO at + * first submission time. In Xe the key is instead assigned at BO + * creation time, so the assign variable must always be false. + */ + if (assign) + return -EINVAL; + + return xe_pxp_obj_key_check(pxp, obj); } #endif diff --git a/drivers/gpu/drm/xe/display/intel_bo.c b/drivers/gpu/drm/xe/display/intel_bo.c index b463f5bd4eed1..27437c22bd703 100644 --- a/drivers/gpu/drm/xe/display/intel_bo.c +++ b/drivers/gpu/drm/xe/display/intel_bo.c @@ -25,7 +25,7 @@ bool intel_bo_is_shmem(struct drm_gem_object *obj) bool intel_bo_is_protected(struct drm_gem_object *obj) { - return false; + return xe_bo_is_protected(gem_to_xe_bo(obj)); } void intel_bo_flush_if_display(struct drm_gem_object *obj) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index c32201123d448..6812164e1470a 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -6,6 +6,7 @@ #include "xe_bo.h" #include +#include #include #include @@ -26,6 +27,7 @@ #include "xe_migrate.h" #include "xe_pm.h" #include "xe_preempt_fence.h" +#include "xe_pxp.h" #include "xe_res_cursor.h" #include "xe_trace_bo.h" #include "xe_ttm_stolen_mgr.h" @@ -2155,6 +2157,93 @@ void xe_bo_vunmap(struct xe_bo *bo) __xe_bo_vunmap(bo); } +static int gem_create_set_pxp_type(struct xe_device *xe, struct xe_bo *bo, u64 value) +{ + if (value == DRM_XE_PXP_TYPE_NONE) + return 0; + + /* we only support DRM_XE_PXP_TYPE_HWDRM for now */ + if (XE_IOCTL_DBG(xe, value != DRM_XE_PXP_TYPE_HWDRM)) + return -EINVAL; + + return xe_pxp_key_assign(xe->pxp, bo); +} + +typedef int (*xe_gem_create_set_property_fn)(struct xe_device *xe, + struct xe_bo *bo, + u64 value); + +static const xe_gem_create_set_property_fn gem_create_set_property_funcs[] = { + [DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY] = gem_create_set_pxp_type, +}; + +static int gem_create_user_ext_set_property(struct xe_device *xe, + struct xe_bo *bo, + u64 extension) +{ + u64 __user *address = u64_to_user_ptr(extension); + struct drm_xe_ext_set_property ext; + int err; + u32 idx; + + err = __copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(xe, err)) + return -EFAULT; + + if (XE_IOCTL_DBG(xe, ext.property >= + ARRAY_SIZE(gem_create_set_property_funcs)) || + XE_IOCTL_DBG(xe, ext.pad) || + XE_IOCTL_DBG(xe, ext.property != DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY)) + return -EINVAL; + + idx = array_index_nospec(ext.property, ARRAY_SIZE(gem_create_set_property_funcs)); + if (!gem_create_set_property_funcs[idx]) + return -EINVAL; + + return gem_create_set_property_funcs[idx](xe, bo, ext.value); +} + +typedef int (*xe_gem_create_user_extension_fn)(struct xe_device *xe, + struct xe_bo *bo, + u64 extension); + +static const xe_gem_create_user_extension_fn gem_create_user_extension_funcs[] = { + [DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY] = gem_create_user_ext_set_property, +}; + +#define MAX_USER_EXTENSIONS 16 +static int gem_create_user_extensions(struct xe_device *xe, struct xe_bo *bo, + u64 extensions, int ext_number) +{ + u64 __user *address = u64_to_user_ptr(extensions); + struct drm_xe_user_extension ext; + int err; + u32 idx; + + if (XE_IOCTL_DBG(xe, ext_number >= MAX_USER_EXTENSIONS)) + return -E2BIG; + + err = __copy_from_user(&ext, address, sizeof(ext)); + if (XE_IOCTL_DBG(xe, err)) + return -EFAULT; + + if (XE_IOCTL_DBG(xe, ext.pad) || + XE_IOCTL_DBG(xe, ext.name >= ARRAY_SIZE(gem_create_user_extension_funcs))) + return -EINVAL; + + idx = array_index_nospec(ext.name, + ARRAY_SIZE(gem_create_user_extension_funcs)); + err = gem_create_user_extension_funcs[idx](xe, bo, extensions); + if (XE_IOCTL_DBG(xe, err)) + return err; + + if (ext.next_extension) + return gem_create_user_extensions(xe, bo, ext.next_extension, + ++ext_number); + + return 0; +} + int xe_gem_create_ioctl(struct drm_device *dev, void *data, struct drm_file *file) { @@ -2167,8 +2256,7 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data, u32 handle; int err; - if (XE_IOCTL_DBG(xe, args->extensions) || - XE_IOCTL_DBG(xe, args->pad[0] || args->pad[1] || args->pad[2]) || + if (XE_IOCTL_DBG(xe, args->pad[0] || args->pad[1] || args->pad[2]) || XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1])) return -EINVAL; @@ -2250,6 +2338,12 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data, goto out_vm; } + if (args->extensions) { + err = gem_create_user_extensions(xe, bo, args->extensions, 0); + if (err) + goto out_bulk; + } + err = drm_gem_handle_create(file, &bo->ttm.base, &handle); if (err) goto out_bulk; diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h index 04995c5ced320..f09b9315721b4 100644 --- a/drivers/gpu/drm/xe/xe_bo.h +++ b/drivers/gpu/drm/xe/xe_bo.h @@ -186,6 +186,11 @@ static inline bool xe_bo_is_pinned(struct xe_bo *bo) return bo->ttm.pin_count; } +static inline bool xe_bo_is_protected(const struct xe_bo *bo) +{ + return bo->pxp_key_instance; +} + static inline void xe_bo_unpin_map_no_vm(struct xe_bo *bo) { if (likely(bo)) { diff --git a/drivers/gpu/drm/xe/xe_bo_types.h b/drivers/gpu/drm/xe/xe_bo_types.h index 46dc9e4e3e46a..60c522866500c 100644 --- a/drivers/gpu/drm/xe/xe_bo_types.h +++ b/drivers/gpu/drm/xe/xe_bo_types.h @@ -57,6 +57,12 @@ struct xe_bo { */ struct list_head client_link; #endif + /** + * @pxp_key_instance: PXP key instance this BO was created against. A + * 0 in this variable indicates that the BO does not use PXP encryption. + */ + u32 pxp_key_instance; + /** @freed: List node for delayed put. */ struct llist_node freed; /** @update_index: Update index if PT BO */ diff --git a/drivers/gpu/drm/xe/xe_exec.c b/drivers/gpu/drm/xe/xe_exec.c index df8ce550deb40..b75adfc99fb7c 100644 --- a/drivers/gpu/drm/xe/xe_exec.c +++ b/drivers/gpu/drm/xe/xe_exec.c @@ -262,6 +262,12 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) goto err_exec; } + if (xe_exec_queue_uses_pxp(q)) { + err = xe_vm_validate_protected(q->vm); + if (err) + goto err_exec; + } + job = xe_sched_job_create(q, xe_exec_queue_is_parallel(q) ? addresses : &args->address); if (IS_ERR(job)) { diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 24aef5c0f04a3..8060b4050be81 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -8,6 +8,8 @@ #include #include +#include "xe_bo.h" +#include "xe_bo_types.h" #include "xe_device_types.h" #include "xe_exec_queue.h" #include "xe_force_wake.h" @@ -185,6 +187,9 @@ static void pxp_terminate(struct xe_pxp *pxp) pxp_invalidate_queues(pxp); + if (pxp->status == XE_PXP_ACTIVE) + pxp->key_instance++; + /* * If we have a termination already in progress, we need to wait for * it to complete before queueing another one. Once the first @@ -385,6 +390,8 @@ int xe_pxp_init(struct xe_device *xe) pxp->xe = xe; pxp->gt = gt; + pxp->key_instance = 1; + /* * we'll use the completions to check if there is an action pending, * so we start them as completed and we reinit it when an action is @@ -689,3 +696,86 @@ static void pxp_invalidate_queues(struct xe_pxp *pxp) spin_unlock_irq(&pxp->queues.lock); } + +/** + * xe_pxp_key_assign - mark a BO as using the current PXP key iteration + * @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled) + * @bo: the BO to mark + * + * Returns: -ENODEV if PXP is disabled, 0 otherwise. + */ +int xe_pxp_key_assign(struct xe_pxp *pxp, struct xe_bo *bo) +{ + if (!xe_pxp_is_enabled(pxp)) + return -ENODEV; + + xe_assert(pxp->xe, !bo->pxp_key_instance); + + /* + * Note that the PXP key handling is inherently racey, because the key + * can theoretically change at any time (although it's unlikely to do + * so without triggers), even right after we copy it. Taking a lock + * wouldn't help because the value might still change as soon as we + * release the lock. + * Userspace needs to handle the fact that their BOs can go invalid at + * any point. + */ + bo->pxp_key_instance = pxp->key_instance; + + return 0; +} + +/** + * xe_pxp_bo_key_check - check if the key used by a xe_bo is valid + * @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled) + * @bo: the BO we want to check + * + * Checks whether a BO was encrypted with the current key or an obsolete one. + * + * Returns: 0 if the key is valid, -ENODEV if PXP is disabled, -EINVAL if the + * BO is not using PXP, -ENOEXEC if the key is not valid. + */ +int xe_pxp_bo_key_check(struct xe_pxp *pxp, struct xe_bo *bo) +{ + if (!xe_pxp_is_enabled(pxp)) + return -ENODEV; + + if (!xe_bo_is_protected(bo)) + return -EINVAL; + + xe_assert(pxp->xe, bo->pxp_key_instance); + + /* + * Note that the PXP key handling is inherently racey, because the key + * can theoretically change at any time (although it's unlikely to do + * so without triggers), even right after we check it. Taking a lock + * wouldn't help because the value might still change as soon as we + * release the lock. + * We mitigate the risk by checking the key at multiple points (on each + * submission involving the BO and right before flipping it on the + * display), but there is still a very small chance that we could + * operate on an invalid BO for a single submission or a single frame + * flip. This is a compromise made to protect the encrypted data (which + * is what the key termination is for). + */ + if (bo->pxp_key_instance != pxp->key_instance) + return -ENOEXEC; + + return 0; +} + +/** + * xe_pxp_obj_key_check - check if the key used by a drm_gem_obj is valid + * @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled) + * @obj: the drm_gem_obj we want to check + * + * Checks whether a drm_gem_obj was encrypted with the current key or an + * obsolete one. + * + * Returns: 0 if the key is valid, -ENODEV if PXP is disabled, -EINVAL if the + * obj is not using PXP, -ENOEXEC if the key is not valid. + */ +int xe_pxp_obj_key_check(struct xe_pxp *pxp, struct drm_gem_object *obj) +{ + return xe_pxp_bo_key_check(pxp, gem_to_xe_bo(obj)); +} diff --git a/drivers/gpu/drm/xe/xe_pxp.h b/drivers/gpu/drm/xe/xe_pxp.h index 868813cc84b9e..3dd70eac9da6d 100644 --- a/drivers/gpu/drm/xe/xe_pxp.h +++ b/drivers/gpu/drm/xe/xe_pxp.h @@ -8,6 +8,8 @@ #include +struct drm_gem_object; +struct xe_bo; struct xe_device; struct xe_exec_queue; struct xe_pxp; @@ -23,4 +25,8 @@ int xe_pxp_exec_queue_set_type(struct xe_pxp *pxp, struct xe_exec_queue *q, u8 t int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q); void xe_pxp_exec_queue_remove(struct xe_pxp *pxp, struct xe_exec_queue *q); +int xe_pxp_key_assign(struct xe_pxp *pxp, struct xe_bo *bo); +int xe_pxp_bo_key_check(struct xe_pxp *pxp, struct xe_bo *bo); +int xe_pxp_obj_key_check(struct xe_pxp *pxp, struct drm_gem_object *obj); + #endif /* __XE_PXP_H__ */ diff --git a/drivers/gpu/drm/xe/xe_pxp_types.h b/drivers/gpu/drm/xe/xe_pxp_types.h index bd741720f67d2..8e4569f0173df 100644 --- a/drivers/gpu/drm/xe/xe_pxp_types.h +++ b/drivers/gpu/drm/xe/xe_pxp_types.h @@ -112,6 +112,17 @@ struct xe_pxp { /** @queues.list: list of exec_queues that use PXP */ struct list_head list; } queues; + + /** + * @key_instance: keep track of the current iteration of the PXP key. + * Note that, due to the time needed for PXP termination and re-start + * to complete, the minimum time between 2 subsequent increases of this + * variable is 50ms, and even that only if there is a continuous attack; + * normal behavior is for this to increase much much slower than that. + * This means that we don't expect this to ever wrap and don't implement + * that case in the code. + */ + u32 key_instance; }; #endif /* __XE_PXP_TYPES_H__ */ diff --git a/drivers/gpu/drm/xe/xe_vm.c b/drivers/gpu/drm/xe/xe_vm.c index b9270d059e182..d664f2e418b26 100644 --- a/drivers/gpu/drm/xe/xe_vm.c +++ b/drivers/gpu/drm/xe/xe_vm.c @@ -33,6 +33,7 @@ #include "xe_pm.h" #include "xe_preempt_fence.h" #include "xe_pt.h" +#include "xe_pxp.h" #include "xe_res_cursor.h" #include "xe_sync.h" #include "xe_trace_bo.h" @@ -2726,7 +2727,8 @@ ALLOW_ERROR_INJECTION(vm_bind_ioctl_ops_execute, ERRNO); (DRM_XE_VM_BIND_FLAG_READONLY | \ DRM_XE_VM_BIND_FLAG_IMMEDIATE | \ DRM_XE_VM_BIND_FLAG_NULL | \ - DRM_XE_VM_BIND_FLAG_DUMPABLE) + DRM_XE_VM_BIND_FLAG_DUMPABLE | \ + DRM_XE_VM_BIND_FLAG_CHECK_PXP) #ifdef TEST_VM_OPS_ERROR #define SUPPORTED_FLAGS (SUPPORTED_FLAGS_STUB | FORCE_OP_ERROR) @@ -2889,7 +2891,7 @@ static void xe_vma_ops_init(struct xe_vma_ops *vops, struct xe_vm *vm, static int xe_vm_bind_ioctl_validate_bo(struct xe_device *xe, struct xe_bo *bo, u64 addr, u64 range, u64 obj_offset, - u16 pat_index) + u16 pat_index, u32 op, u32 bind_flags) { u16 coh_mode; @@ -2933,6 +2935,12 @@ static int xe_vm_bind_ioctl_validate_bo(struct xe_device *xe, struct xe_bo *bo, return -EINVAL; } + /* If a BO is protected it can only be mapped if the key is still valid */ + if ((bind_flags & DRM_XE_VM_BIND_FLAG_CHECK_PXP) && xe_bo_is_protected(bo) && + op != DRM_XE_VM_BIND_OP_UNMAP && op != DRM_XE_VM_BIND_OP_UNMAP_ALL) + if (XE_IOCTL_DBG(xe, xe_pxp_bo_key_check(xe->pxp, bo) != 0)) + return -ENOEXEC; + return 0; } @@ -3022,6 +3030,8 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file) u32 obj = bind_ops[i].obj; u64 obj_offset = bind_ops[i].obj_offset; u16 pat_index = bind_ops[i].pat_index; + u32 op = bind_ops[i].op; + u32 bind_flags = bind_ops[i].flags; if (!obj) continue; @@ -3034,7 +3044,8 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file) bos[i] = gem_to_xe_bo(gem_obj); err = xe_vm_bind_ioctl_validate_bo(xe, bos[i], addr, range, - obj_offset, pat_index); + obj_offset, pat_index, op, + bind_flags); if (err) goto put_obj; } @@ -3334,6 +3345,35 @@ int xe_vm_invalidate_vma(struct xe_vma *vma) return ret; } +int xe_vm_validate_protected(struct xe_vm *vm) +{ + struct drm_gpuva *gpuva; + int err = 0; + + if (!vm) + return -ENODEV; + + mutex_lock(&vm->snap_mutex); + + drm_gpuvm_for_each_va(gpuva, &vm->gpuvm) { + struct xe_vma *vma = gpuva_to_vma(gpuva); + struct xe_bo *bo = vma->gpuva.gem.obj ? + gem_to_xe_bo(vma->gpuva.gem.obj) : NULL; + + if (!bo) + continue; + + if (xe_bo_is_protected(bo)) { + err = xe_pxp_bo_key_check(vm->xe->pxp, bo); + if (err) + break; + } + } + + mutex_unlock(&vm->snap_mutex); + return err; +} + struct xe_vm_snapshot { unsigned long num_snaps; struct { diff --git a/drivers/gpu/drm/xe/xe_vm.h b/drivers/gpu/drm/xe/xe_vm.h index 0a2fa6c0815b7..f66075f8a6fe8 100644 --- a/drivers/gpu/drm/xe/xe_vm.h +++ b/drivers/gpu/drm/xe/xe_vm.h @@ -215,6 +215,8 @@ struct dma_fence *xe_vma_rebind(struct xe_vm *vm, struct xe_vma *vma, int xe_vm_invalidate_vma(struct xe_vma *vma); +int xe_vm_validate_protected(struct xe_vm *vm); + static inline void xe_vm_queue_rebind_worker(struct xe_vm *vm) { xe_assert(vm->xe, xe_vm_in_preempt_fence_mode(vm)); diff --git a/include/uapi/drm/xe_drm.h b/include/uapi/drm/xe_drm.h index 112fd27f3c755..892f54d3aa091 100644 --- a/include/uapi/drm/xe_drm.h +++ b/include/uapi/drm/xe_drm.h @@ -778,8 +778,23 @@ struct drm_xe_device_query { * - %DRM_XE_GEM_CPU_CACHING_WC - Allocate the pages as write-combined. This * is uncached. Scanout surfaces should likely use this. All objects * that can be placed in VRAM must use this. + * + * This ioctl supports setting the following properties via the + * %DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY extension, which uses the + * generic @drm_xe_ext_set_property struct: + * + * - %DRM_XE_GEM_CREATE_SET_PROPERTY_PXP_TYPE - set the type of PXP session + * this object will be used with. Valid values are listed in enum + * drm_xe_pxp_session_type. %DRM_XE_PXP_TYPE_NONE is the default behavior, so + * there is no need to explicitly set that. Objects used with session of type + * %DRM_XE_PXP_TYPE_HWDRM will be marked as invalid if a PXP invalidation + * event occurs after their creation. Attempting to flip an invalid object + * will cause a black frame to be displayed instead. Submissions with invalid + * objects mapped in the VM will be rejected. */ struct drm_xe_gem_create { +#define DRM_XE_GEM_CREATE_EXTENSION_SET_PROPERTY 0 +#define DRM_XE_GEM_CREATE_SET_PROPERTY_PXP_TYPE 0 /** @extensions: Pointer to the first extension struct, if any */ __u64 extensions; @@ -968,6 +983,9 @@ struct drm_xe_vm_destroy { * will only be valid for DRM_XE_VM_BIND_OP_MAP operations, the BO * handle MBZ, and the BO offset MBZ. This flag is intended to * implement VK sparse bindings. + * - %DRM_XE_VM_BIND_FLAG_CHECK_PXP - If the object is encrypted via PXP, + * reject the binding if the encryption key is no longer valid. This + * flag has no effect on BOs that are not marked as using PXP. */ struct drm_xe_vm_bind_op { /** @extensions: Pointer to the first extension struct, if any */ @@ -1058,6 +1076,7 @@ struct drm_xe_vm_bind_op { #define DRM_XE_VM_BIND_FLAG_IMMEDIATE (1 << 1) #define DRM_XE_VM_BIND_FLAG_NULL (1 << 2) #define DRM_XE_VM_BIND_FLAG_DUMPABLE (1 << 3) +#define DRM_XE_VM_BIND_FLAG_CHECK_PXP (1 << 4) /** @flags: Bind flags */ __u32 flags; From 51462211f4a920687ae51823f6a8b0f499546bcc Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:35 -0800 Subject: [PATCH 081/130] drm/xe/pxp: add PXP PM support The HW suspend flow kills all PXP HWDRM sessions, so we need to mark all the queues and BOs as invalid and do a full termination when PXP is next used. v2: rebase v3: rebase on new status flow, defer termination to next PXP use as it makes things much easier and allows us to use the same function for all types of suspend. v4: fix the documentation of the suspend function (John) Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-12-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pm.c | 39 ++++++--- drivers/gpu/drm/xe/xe_pxp.c | 129 +++++++++++++++++++++++++++++- drivers/gpu/drm/xe/xe_pxp.h | 3 + drivers/gpu/drm/xe/xe_pxp_types.h | 7 ++ 4 files changed, 165 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c index c9cc0c091dfdd..35dd1757b40be 100644 --- a/drivers/gpu/drm/xe/xe_pm.c +++ b/drivers/gpu/drm/xe/xe_pm.c @@ -22,6 +22,7 @@ #include "xe_guc.h" #include "xe_irq.h" #include "xe_pcode.h" +#include "xe_pxp.h" #include "xe_trace.h" #include "xe_wa.h" @@ -122,6 +123,10 @@ int xe_pm_suspend(struct xe_device *xe) drm_dbg(&xe->drm, "Suspending device\n"); trace_xe_pm_suspend(xe, __builtin_return_address(0)); + err = xe_pxp_pm_suspend(xe->pxp); + if (err) + goto err; + for_each_gt(gt, xe, id) xe_gt_suspend_prepare(gt); @@ -130,14 +135,12 @@ int xe_pm_suspend(struct xe_device *xe) /* FIXME: Super racey... */ err = xe_bo_evict_all(xe); if (err) - goto err; + goto err_pxp; for_each_gt(gt, xe, id) { err = xe_gt_suspend(gt); - if (err) { - xe_display_pm_resume(xe); - goto err; - } + if (err) + goto err_display; } xe_irq_suspend(xe); @@ -146,6 +149,11 @@ int xe_pm_suspend(struct xe_device *xe) drm_dbg(&xe->drm, "Device suspended\n"); return 0; + +err_display: + xe_display_pm_resume(xe); +err_pxp: + xe_pxp_pm_resume(xe->pxp); err: drm_dbg(&xe->drm, "Device suspend failed %d\n", err); return err; @@ -195,6 +203,8 @@ int xe_pm_resume(struct xe_device *xe) if (err) goto err; + xe_pxp_pm_resume(xe->pxp); + drm_dbg(&xe->drm, "Device resumed\n"); return 0; err: @@ -389,6 +399,10 @@ int xe_pm_runtime_suspend(struct xe_device *xe) */ xe_rpm_lockmap_acquire(xe); + err = xe_pxp_pm_suspend(xe->pxp); + if (err) + goto out; + /* * Applying lock for entire list op as xe_ttm_bo_destroy and xe_bo_move_notify * also checks and deletes bo entry from user fault list. @@ -404,22 +418,27 @@ int xe_pm_runtime_suspend(struct xe_device *xe) if (xe->d3cold.allowed) { err = xe_bo_evict_all(xe); if (err) - goto out; + goto out_resume; } for_each_gt(gt, xe, id) { err = xe_gt_suspend(gt); if (err) - goto out; + goto out_resume; } xe_irq_suspend(xe); xe_display_pm_runtime_suspend_late(xe); + xe_rpm_lockmap_release(xe); + xe_pm_write_callback_task(xe, NULL); + return 0; + +out_resume: + xe_display_pm_runtime_resume(xe); + xe_pxp_pm_resume(xe->pxp); out: - if (err) - xe_display_pm_runtime_resume(xe); xe_rpm_lockmap_release(xe); xe_pm_write_callback_task(xe, NULL); return err; @@ -472,6 +491,8 @@ int xe_pm_runtime_resume(struct xe_device *xe) goto out; } + xe_pxp_pm_resume(xe->pxp); + out: xe_rpm_lockmap_release(xe); xe_pm_write_callback_task(xe, NULL); diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 8060b4050be81..5e7a1688a771c 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -132,6 +132,14 @@ static int pxp_wait_for_session_state(struct xe_pxp *pxp, u32 id, bool in_play) static void pxp_invalidate_queues(struct xe_pxp *pxp); +static void pxp_invalidate_state(struct xe_pxp *pxp) +{ + pxp_invalidate_queues(pxp); + + if (pxp->status == XE_PXP_ACTIVE) + pxp->key_instance++; +} + static int pxp_terminate_hw(struct xe_pxp *pxp) { struct xe_gt *gt = pxp->gt; @@ -185,10 +193,16 @@ static void pxp_terminate(struct xe_pxp *pxp) mutex_lock(&pxp->mutex); - pxp_invalidate_queues(pxp); + pxp_invalidate_state(pxp); - if (pxp->status == XE_PXP_ACTIVE) - pxp->key_instance++; + /* + * we'll mark the status as needing termination on resume, so no need to + * emit a termination now. + */ + if (pxp->status == XE_PXP_SUSPENDED) { + mutex_unlock(&pxp->mutex); + return; + } /* * If we have a termination already in progress, we need to wait for @@ -219,11 +233,13 @@ static void pxp_terminate(struct xe_pxp *pxp) static void pxp_terminate_complete(struct xe_pxp *pxp) { /* - * We expect PXP to be in one of 2 states when we get here: + * We expect PXP to be in one of 3 states when we get here: * - XE_PXP_TERMINATION_IN_PROGRESS: a single termination event was * requested and it is now completing, so we're ready to start. * - XE_PXP_NEEDS_ADDITIONAL_TERMINATION: a second termination was * requested while the first one was still being processed. + * - XE_PXP_SUSPENDED: PXP is now suspended, so we defer everything to + * when we come back on resume. */ mutex_lock(&pxp->mutex); @@ -234,6 +250,9 @@ static void pxp_terminate_complete(struct xe_pxp *pxp) case XE_PXP_NEEDS_ADDITIONAL_TERMINATION: pxp->status = XE_PXP_NEEDS_TERMINATION; break; + case XE_PXP_SUSPENDED: + /* Nothing to do */ + break; default: drm_err(&pxp->xe->drm, "PXP termination complete while status was %u\n", @@ -391,6 +410,7 @@ int xe_pxp_init(struct xe_device *xe) pxp->gt = gt; pxp->key_instance = 1; + pxp->last_suspend_key_instance = 1; /* * we'll use the completions to check if there is an action pending, @@ -574,6 +594,7 @@ int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q) XE_WARN_ON(completion_done(&pxp->termination)); mutex_unlock(&pxp->mutex); goto wait_for_idle; + case XE_PXP_SUSPENDED: default: drm_err(&pxp->xe->drm, "unexpected state during PXP start: %u\n", pxp->status); ret = -EIO; @@ -779,3 +800,103 @@ int xe_pxp_obj_key_check(struct xe_pxp *pxp, struct drm_gem_object *obj) { return xe_pxp_bo_key_check(pxp, gem_to_xe_bo(obj)); } + +/** + * xe_pxp_pm_suspend - prepare PXP for HW suspend + * @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled) + * + * Makes sure all PXP actions have completed and invalidates all PXP queues + * and objects before we go into a suspend state. + * + * Returns: 0 if successful, a negative errno value otherwise. + */ +int xe_pxp_pm_suspend(struct xe_pxp *pxp) +{ + int ret = 0; + + if (!xe_pxp_is_enabled(pxp)) + return 0; + +wait_for_activation: + if (!wait_for_completion_timeout(&pxp->activation, + msecs_to_jiffies(PXP_ACTIVATION_TIMEOUT_MS))) + ret = -ETIMEDOUT; + + mutex_lock(&pxp->mutex); + + switch (pxp->status) { + case XE_PXP_ERROR: + case XE_PXP_READY_TO_START: + case XE_PXP_SUSPENDED: + case XE_PXP_TERMINATION_IN_PROGRESS: + case XE_PXP_NEEDS_ADDITIONAL_TERMINATION: + /* + * If PXP is not running there is nothing to cleanup. If there + * is a termination pending then no need to issue another one. + */ + break; + case XE_PXP_START_IN_PROGRESS: + mutex_unlock(&pxp->mutex); + goto wait_for_activation; + case XE_PXP_NEEDS_TERMINATION: + /* If PXP was never used we can skip the cleanup */ + if (pxp->key_instance == pxp->last_suspend_key_instance) + break; + fallthrough; + case XE_PXP_ACTIVE: + pxp_invalidate_state(pxp); + break; + default: + drm_err(&pxp->xe->drm, "unexpected state during PXP suspend: %u", + pxp->status); + ret = -EIO; + goto out; + } + + /* + * We set this even if we were in error state, hoping the suspend clears + * the error. Worse case we fail again and go in error state again. + */ + pxp->status = XE_PXP_SUSPENDED; + + mutex_unlock(&pxp->mutex); + + /* + * if there is a termination in progress, wait for it. + * We need to wait outside the lock because the completion is done from + * within the lock + */ + if (!wait_for_completion_timeout(&pxp->termination, + msecs_to_jiffies(PXP_TERMINATION_TIMEOUT_MS))) + ret = -ETIMEDOUT; + + pxp->last_suspend_key_instance = pxp->key_instance; + +out: + return ret; +} + +/** + * xe_pxp_pm_resume - re-init PXP after HW suspend + * @pxp: the xe->pxp pointer (it will be NULL if PXP is disabled) + */ +void xe_pxp_pm_resume(struct xe_pxp *pxp) +{ + int err; + + if (!xe_pxp_is_enabled(pxp)) + return; + + err = kcr_pxp_enable(pxp); + + mutex_lock(&pxp->mutex); + + xe_assert(pxp->xe, pxp->status == XE_PXP_SUSPENDED); + + if (err) + pxp->status = XE_PXP_ERROR; + else + pxp->status = XE_PXP_NEEDS_TERMINATION; + + mutex_unlock(&pxp->mutex); +} diff --git a/drivers/gpu/drm/xe/xe_pxp.h b/drivers/gpu/drm/xe/xe_pxp.h index 3dd70eac9da6d..546b156d63aa5 100644 --- a/drivers/gpu/drm/xe/xe_pxp.h +++ b/drivers/gpu/drm/xe/xe_pxp.h @@ -21,6 +21,9 @@ int xe_pxp_get_readiness_status(struct xe_pxp *pxp); int xe_pxp_init(struct xe_device *xe); void xe_pxp_irq_handler(struct xe_device *xe, u16 iir); +int xe_pxp_pm_suspend(struct xe_pxp *pxp); +void xe_pxp_pm_resume(struct xe_pxp *pxp); + int xe_pxp_exec_queue_set_type(struct xe_pxp *pxp, struct xe_exec_queue *q, u8 type); int xe_pxp_exec_queue_add(struct xe_pxp *pxp, struct xe_exec_queue *q); void xe_pxp_exec_queue_remove(struct xe_pxp *pxp, struct xe_exec_queue *q); diff --git a/drivers/gpu/drm/xe/xe_pxp_types.h b/drivers/gpu/drm/xe/xe_pxp_types.h index 8e4569f0173df..53e9d48d10fb8 100644 --- a/drivers/gpu/drm/xe/xe_pxp_types.h +++ b/drivers/gpu/drm/xe/xe_pxp_types.h @@ -27,6 +27,7 @@ enum xe_pxp_status { XE_PXP_READY_TO_START, XE_PXP_START_IN_PROGRESS, XE_PXP_ACTIVE, + XE_PXP_SUSPENDED, }; /** @@ -123,6 +124,12 @@ struct xe_pxp { * that case in the code. */ u32 key_instance; + /** + * @last_suspend_key_instance: value of key_instance at the last + * suspend. Used to check if any PXP session has been created between + * suspend cycles. + */ + u32 last_suspend_key_instance; }; #endif /* __XE_PXP_TYPES_H__ */ From 385a8015b21469f249cdf30453f2c93d32405aa9 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:36 -0800 Subject: [PATCH 082/130] drm/xe/pxp: Add PXP debugfs support This patch introduces 2 PXP debugfs entries: - info: prints the current PXP status and key instance - terminate: simulate a termination interrupt The first one is useful for debug, while the second one can be used for testing the termination flow. v2: move the info prints inside the lock (John) Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-13-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/Makefile | 1 + drivers/gpu/drm/xe/xe_debugfs.c | 3 + drivers/gpu/drm/xe/xe_pxp_debugfs.c | 120 ++++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_pxp_debugfs.h | 13 +++ 4 files changed, 137 insertions(+) create mode 100644 drivers/gpu/drm/xe/xe_pxp_debugfs.c create mode 100644 drivers/gpu/drm/xe/xe_pxp_debugfs.h diff --git a/drivers/gpu/drm/xe/Makefile b/drivers/gpu/drm/xe/Makefile index 720d13c16fa54..be73362ef334e 100644 --- a/drivers/gpu/drm/xe/Makefile +++ b/drivers/gpu/drm/xe/Makefile @@ -88,6 +88,7 @@ xe-y += xe_bb.o \ xe_pt.o \ xe_pt_walk.o \ xe_pxp.o \ + xe_pxp_debugfs.o \ xe_pxp_submit.o \ xe_query.o \ xe_range_fence.o \ diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 492b4877433f1..56cb3788e7523 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -18,6 +18,7 @@ #include "xe_gt_printk.h" #include "xe_guc_ads.h" #include "xe_pm.h" +#include "xe_pxp_debugfs.h" #include "xe_sriov.h" #include "xe_step.h" @@ -230,5 +231,7 @@ void xe_debugfs_register(struct xe_device *xe) for_each_gt(gt, xe, id) xe_gt_debugfs_register(gt); + xe_pxp_debugfs_register(xe->pxp); + fault_create_debugfs_attr("fail_gt_reset", root, >_reset_failure); } diff --git a/drivers/gpu/drm/xe/xe_pxp_debugfs.c b/drivers/gpu/drm/xe/xe_pxp_debugfs.c new file mode 100644 index 0000000000000..ccfbacf08efc1 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pxp_debugfs.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: MIT +/* + * Copyright © 2024 Intel Corporation + */ + +#include "xe_pxp_debugfs.h" + +#include + +#include +#include +#include + +#include "xe_device.h" +#include "xe_pxp.h" +#include "xe_pxp_types.h" +#include "regs/xe_irq_regs.h" + +static struct xe_pxp *node_to_pxp(struct drm_info_node *node) +{ + return node->info_ent->data; +} + +static const char *pxp_status_to_str(struct xe_pxp *pxp) +{ + lockdep_assert_held(&pxp->mutex); + + switch (pxp->status) { + case XE_PXP_ERROR: + return "error"; + case XE_PXP_NEEDS_TERMINATION: + return "needs termination"; + case XE_PXP_TERMINATION_IN_PROGRESS: + return "termination in progress"; + case XE_PXP_READY_TO_START: + return "ready to start"; + case XE_PXP_ACTIVE: + return "active"; + case XE_PXP_SUSPENDED: + return "suspended"; + default: + return "unknown"; + } +}; + +static int pxp_info(struct seq_file *m, void *data) +{ + struct xe_pxp *pxp = node_to_pxp(m->private); + struct drm_printer p = drm_seq_file_printer(m); + const char *status; + + if (!xe_pxp_is_enabled(pxp)) + return -ENODEV; + + mutex_lock(&pxp->mutex); + status = pxp_status_to_str(pxp); + + drm_printf(&p, "status: %s\n", status); + drm_printf(&p, "instance counter: %u\n", pxp->key_instance); + mutex_unlock(&pxp->mutex); + + return 0; +} + +static int pxp_terminate(struct seq_file *m, void *data) +{ + struct xe_pxp *pxp = node_to_pxp(m->private); + struct drm_printer p = drm_seq_file_printer(m); + + if (!xe_pxp_is_enabled(pxp)) + return -ENODEV; + + /* simulate a termination interrupt */ + spin_lock_irq(&pxp->xe->irq.lock); + xe_pxp_irq_handler(pxp->xe, KCR_PXP_STATE_TERMINATED_INTERRUPT); + spin_unlock_irq(&pxp->xe->irq.lock); + + drm_printf(&p, "PXP termination queued\n"); + + return 0; +} + +static const struct drm_info_list debugfs_list[] = { + {"info", pxp_info, 0}, + {"terminate", pxp_terminate, 0}, +}; + +void xe_pxp_debugfs_register(struct xe_pxp *pxp) +{ + struct drm_minor *minor; + struct drm_info_list *local; + struct dentry *root; + int i; + + if (!xe_pxp_is_enabled(pxp)) + return; + + minor = pxp->xe->drm.primary; + if (!minor->debugfs_root) + return; + +#define DEBUGFS_SIZE (ARRAY_SIZE(debugfs_list) * sizeof(struct drm_info_list)) + local = drmm_kmalloc(&pxp->xe->drm, DEBUGFS_SIZE, GFP_KERNEL); + if (!local) + return; + + memcpy(local, debugfs_list, DEBUGFS_SIZE); +#undef DEBUGFS_SIZE + + for (i = 0; i < ARRAY_SIZE(debugfs_list); ++i) + local[i].data = pxp; + + root = debugfs_create_dir("pxp", minor->debugfs_root); + if (IS_ERR(root)) + return; + + drm_debugfs_create_files(local, + ARRAY_SIZE(debugfs_list), + root, minor); +} diff --git a/drivers/gpu/drm/xe/xe_pxp_debugfs.h b/drivers/gpu/drm/xe/xe_pxp_debugfs.h new file mode 100644 index 0000000000000..988466aad50b3 --- /dev/null +++ b/drivers/gpu/drm/xe/xe_pxp_debugfs.h @@ -0,0 +1,13 @@ +/* SPDX-License-Identifier: MIT */ +/* + * Copyright © 2024 Intel Corporation + */ + +#ifndef __XE_PXP_DEBUGFS_H__ +#define __XE_PXP_DEBUGFS_H__ + +struct xe_pxp; + +void xe_pxp_debugfs_register(struct xe_pxp *pxp); + +#endif /* __XE_PXP_DEBUGFS_H__ */ From 492f8d2030bec7ab6d0adf7f41808d73871f86e7 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Wed, 29 Jan 2025 09:41:37 -0800 Subject: [PATCH 083/130] drm/xe/pxp: Enable PXP for MTL and LNL Now that are the pieces are there, we can turn the feature on. Signed-off-by: Daniele Ceraolo Spurio Reviewed-by: John Harrison Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-14-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pci.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 0a6e58d55682a..feb46a7072818 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -333,11 +333,13 @@ static const struct xe_device_desc mtl_desc = { .require_force_probe = true, PLATFORM(METEORLAKE), .has_display = true, + .has_pxp = true, }; static const struct xe_device_desc lnl_desc = { PLATFORM(LUNARLAKE), .has_display = true, + .has_pxp = true, }; static const struct xe_device_desc bmg_desc = { From e4afdef60562014bc4a5c74384cfe9de84590ca5 Mon Sep 17 00:00:00 2001 From: Sai Teja Pottumuttu Date: Thu, 30 Jan 2025 14:28:03 +0530 Subject: [PATCH 084/130] drm/xe: Refactor dma_mask_size dma_mask_size is more related to the platform than the GT IP. Thus move it to platform descriptors. v2: - Rebase Signed-off-by: Sai Teja Pottumuttu Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20250130085804.4136497-2-sai.teja.pottumuttu@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_pci.c | 22 ++++++++++++++++------ drivers/gpu/drm/xe/xe_pci_types.h | 1 - 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index feb46a7072818..38e6ba091ea5f 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -55,6 +55,8 @@ struct xe_device_desc { enum xe_platform platform; + u8 dma_mask_size; + u8 require_force_probe:1; u8 is_dgfx:1; @@ -85,7 +87,6 @@ static const struct xe_graphics_desc graphics_xelp = { .hw_engine_mask = BIT(XE_HW_ENGINE_RCS0) | BIT(XE_HW_ENGINE_BCS0), - .dma_mask_size = 39, .va_bits = 48, .vm_max_level = 3, }; @@ -97,14 +98,12 @@ static const struct xe_graphics_desc graphics_xelpp = { .hw_engine_mask = BIT(XE_HW_ENGINE_RCS0) | BIT(XE_HW_ENGINE_BCS0), - .dma_mask_size = 39, .va_bits = 48, .vm_max_level = 3, }; #define XE_HP_FEATURES \ .has_range_tlb_invalidation = true, \ - .dma_mask_size = 46, \ .va_bits = 48, \ .vm_max_level = 3 @@ -139,7 +138,6 @@ static const struct xe_graphics_desc graphics_xehpc = { BIT(XE_HW_ENGINE_CCS2) | BIT(XE_HW_ENGINE_CCS3), XE_HP_FEATURES, - .dma_mask_size = 52, .max_remote_tiles = 1, .va_bits = 57, .vm_max_level = 4, @@ -160,7 +158,6 @@ static const struct xe_graphics_desc graphics_xelpg = { }; #define XE2_GFX_FEATURES \ - .dma_mask_size = 46, \ .has_asid = 1, \ .has_atomic_enable_pte_bit = 1, \ .has_flat_ccs = 1, \ @@ -220,6 +217,7 @@ static const struct xe_device_desc tgl_desc = { .graphics = &graphics_xelp, .media = &media_xem, PLATFORM(TIGERLAKE), + .dma_mask_size = 39, .has_display = true, .has_llc = true, .require_force_probe = true, @@ -229,6 +227,7 @@ static const struct xe_device_desc rkl_desc = { .graphics = &graphics_xelp, .media = &media_xem, PLATFORM(ROCKETLAKE), + .dma_mask_size = 39, .has_display = true, .has_llc = true, .require_force_probe = true, @@ -240,6 +239,7 @@ static const struct xe_device_desc adl_s_desc = { .graphics = &graphics_xelp, .media = &media_xem, PLATFORM(ALDERLAKE_S), + .dma_mask_size = 39, .has_display = true, .has_llc = true, .require_force_probe = true, @@ -255,6 +255,7 @@ static const struct xe_device_desc adl_p_desc = { .graphics = &graphics_xelp, .media = &media_xem, PLATFORM(ALDERLAKE_P), + .dma_mask_size = 39, .has_display = true, .has_llc = true, .require_force_probe = true, @@ -268,6 +269,7 @@ static const struct xe_device_desc adl_n_desc = { .graphics = &graphics_xelp, .media = &media_xem, PLATFORM(ALDERLAKE_N), + .dma_mask_size = 39, .has_display = true, .has_llc = true, .require_force_probe = true, @@ -281,6 +283,7 @@ static const struct xe_device_desc dg1_desc = { .media = &media_xem, DGFX_FEATURES, PLATFORM(DG1), + .dma_mask_size = 39, .has_display = true, .has_heci_gscfi = 1, .require_force_probe = true, @@ -304,6 +307,7 @@ static const u16 dg2_g12_ids[] = { INTEL_DG2_G12_IDS(NOP), 0 }; static const struct xe_device_desc ats_m_desc = { .graphics = &graphics_xehpg, .media = &media_xehpm, + .dma_mask_size = 46, .require_force_probe = true, DG2_FEATURES, @@ -313,6 +317,7 @@ static const struct xe_device_desc ats_m_desc = { static const struct xe_device_desc dg2_desc = { .graphics = &graphics_xehpg, .media = &media_xehpm, + .dma_mask_size = 46, .require_force_probe = true, DG2_FEATURES, @@ -323,6 +328,7 @@ static const __maybe_unused struct xe_device_desc pvc_desc = { .graphics = &graphics_xehpc, DGFX_FEATURES, PLATFORM(PVC), + .dma_mask_size = 52, .has_display = false, .has_heci_gscfi = 1, .require_force_probe = true, @@ -332,12 +338,14 @@ static const struct xe_device_desc mtl_desc = { /* .graphics and .media determined via GMD_ID */ .require_force_probe = true, PLATFORM(METEORLAKE), + .dma_mask_size = 46, .has_display = true, .has_pxp = true, }; static const struct xe_device_desc lnl_desc = { PLATFORM(LUNARLAKE), + .dma_mask_size = 46, .has_display = true, .has_pxp = true, }; @@ -345,12 +353,14 @@ static const struct xe_device_desc lnl_desc = { static const struct xe_device_desc bmg_desc = { DGFX_FEATURES, PLATFORM(BATTLEMAGE), + .dma_mask_size = 46, .has_display = true, .has_heci_cscfi = 1, }; static const struct xe_device_desc ptl_desc = { PLATFORM(PANTHERLAKE), + .dma_mask_size = 46, .has_display = true, .require_force_probe = true, }; @@ -617,6 +627,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.subplatform = subplatform_desc ? subplatform_desc->subplatform : XE_SUBPLATFORM_NONE; + xe->info.dma_mask_size = desc->dma_mask_size; xe->info.is_dgfx = desc->is_dgfx; xe->info.has_heci_gscfi = desc->has_heci_gscfi; xe->info.has_heci_cscfi = desc->has_heci_cscfi; @@ -682,7 +693,6 @@ static int xe_info_init(struct xe_device *xe, xe->info.graphics_name = graphics_desc->name; xe->info.media_name = media_desc ? media_desc->name : "none"; - xe->info.dma_mask_size = graphics_desc->dma_mask_size; xe->info.vram_flags = graphics_desc->vram_flags; xe->info.va_bits = graphics_desc->va_bits; xe->info.vm_max_level = graphics_desc->vm_max_level; diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h index 873efec5cdee8..7437415a54d54 100644 --- a/drivers/gpu/drm/xe/xe_pci_types.h +++ b/drivers/gpu/drm/xe/xe_pci_types.h @@ -13,7 +13,6 @@ struct xe_graphics_desc { u8 ver; u8 rel; - u8 dma_mask_size; /* available DMA address bits */ u8 va_bits; u8 vm_max_level; u8 vram_flags; From 206fa53fe1f1f73eae61c4330aa31dd6393d959e Mon Sep 17 00:00:00 2001 From: Sai Teja Pottumuttu Date: Thu, 30 Jan 2025 14:28:04 +0530 Subject: [PATCH 085/130] drm/xe: Refactor max_remote_tiles max_remote_tiles is more related to the platform than the GT IP. Thus move it to platform descriptor from graphics descriptor. Note that the FIXME is no more required, thus it can be dropped. v2: Rebase v3: Change the position of comment (MattR) Signed-off-by: Sai Teja Pottumuttu Reviewed-by: Matt Roper Link: https://patchwork.freedesktop.org/patch/msgid/20250130085804.4136497-3-sai.teja.pottumuttu@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_pci.c | 21 +++++++++------------ drivers/gpu/drm/xe/xe_pci_types.h | 2 -- 2 files changed, 9 insertions(+), 14 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 38e6ba091ea5f..cfa1ad7a1f2d3 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -56,6 +56,7 @@ struct xe_device_desc { enum xe_platform platform; u8 dma_mask_size; + u8 max_remote_tiles:2; u8 require_force_probe:1; u8 is_dgfx:1; @@ -138,7 +139,6 @@ static const struct xe_graphics_desc graphics_xehpc = { BIT(XE_HW_ENGINE_CCS2) | BIT(XE_HW_ENGINE_CCS3), XE_HP_FEATURES, - .max_remote_tiles = 1, .va_bits = 57, .vm_max_level = 4, .vram_flags = XE_VRAM_FLAGS_NEED64K, @@ -331,6 +331,7 @@ static const __maybe_unused struct xe_device_desc pvc_desc = { .dma_mask_size = 52, .has_display = false, .has_heci_gscfi = 1, + .max_remote_tiles = 1, .require_force_probe = true, }; @@ -641,6 +642,7 @@ static int xe_info_init_early(struct xe_device *xe, xe->info.probe_display = IS_ENABLED(CONFIG_DRM_XE_DISPLAY) && xe_modparam.probe_display && desc->has_display; + xe->info.tile_count = 1 + desc->max_remote_tiles; err = xe_tile_init_early(xe_device_get_root_tile(xe), xe, 0); if (err) @@ -707,17 +709,6 @@ static int xe_info_init(struct xe_device *xe, xe->info.has_range_tlb_invalidation = graphics_desc->has_range_tlb_invalidation; xe->info.has_usm = graphics_desc->has_usm; - /* - * All platforms have at least one primary GT. Any platform with media - * version 13 or higher has an additional dedicated media GT. And - * depending on the graphics IP there may be additional "remote tiles." - * All of these together determine the overall GT count. - * - * FIXME: 'tile_count' here is misnamed since the rest of the driver - * treats it as the number of GTs rather than just the number of tiles. - */ - xe->info.tile_count = 1 + graphics_desc->max_remote_tiles; - for_each_remote_tile(tile, xe, id) { int err; @@ -726,6 +717,12 @@ static int xe_info_init(struct xe_device *xe, return err; } + /* + * All platforms have at least one primary GT. Any platform with media + * version 13 or higher has an additional dedicated media GT. And + * depending on the graphics IP there may be additional "remote tiles." + * All of these together determine the overall GT count. + */ for_each_tile(tile, xe, id) { gt = tile->primary_gt; gt->info.id = xe->info.gt_count++; diff --git a/drivers/gpu/drm/xe/xe_pci_types.h b/drivers/gpu/drm/xe/xe_pci_types.h index 7437415a54d54..b964238449526 100644 --- a/drivers/gpu/drm/xe/xe_pci_types.h +++ b/drivers/gpu/drm/xe/xe_pci_types.h @@ -19,8 +19,6 @@ struct xe_graphics_desc { u64 hw_engine_mask; /* hardware engines provided by graphics IP */ - u8 max_remote_tiles:2; - u8 has_asid:1; u8 has_atomic_enable_pte_bit:1; u8 has_flat_ccs:1; From 78d5d1e20d1de9422f013338a0f2311448588ba7 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 31 Jan 2025 16:37:13 +0100 Subject: [PATCH 086/130] drm/xe/relay: Don't use GFP_KERNEL for new transactions VFs use a relay transaction during the resume/reset flow and use of the GFP_KERNEL flag may conflict with the reclaim: -> #0 (fs_reclaim){+.+.}-{0:0}: [ ] __lock_acquire+0x1874/0x2bc0 [ ] lock_acquire+0xd2/0x310 [ ] fs_reclaim_acquire+0xc5/0x100 [ ] mempool_alloc_noprof+0x5c/0x1b0 [ ] __relay_get_transaction+0xdc/0xa10 [xe] [ ] relay_send_to+0x251/0xe50 [xe] [ ] xe_guc_relay_send_to_pf+0x79/0x3a0 [xe] [ ] xe_gt_sriov_vf_connect+0x90/0x4d0 [xe] [ ] xe_uc_init_hw+0x157/0x3b0 [xe] [ ] do_gt_restart+0x1ae/0x650 [xe] [ ] xe_gt_resume+0xb6/0x120 [xe] [ ] xe_pm_runtime_resume+0x15b/0x370 [xe] [ ] xe_pci_runtime_resume+0x73/0x90 [xe] [ ] pci_pm_runtime_resume+0xa0/0x100 [ ] __rpm_callback+0x4d/0x170 [ ] rpm_callback+0x64/0x70 [ ] rpm_resume+0x594/0x790 [ ] __pm_runtime_resume+0x4e/0x90 [ ] xe_pm_runtime_get_ioctl+0x9c/0x160 [xe] Since we have a preallocated pool of relay transactions, which should cover all our normal relay use cases, we may use the GFP_NOWAIT flag when allocating new outgoing transactions. Signed-off-by: Michal Wajdeczko Tested-by: Marcin Bernatowicz Reviewed-by: Marcin Bernatowicz Link: https://patchwork.freedesktop.org/patch/msgid/20250131153713.808-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_guc_relay.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_guc_relay.c b/drivers/gpu/drm/xe/xe_guc_relay.c index 8f62de026724c..e5dc94f3e6181 100644 --- a/drivers/gpu/drm/xe/xe_guc_relay.c +++ b/drivers/gpu/drm/xe/xe_guc_relay.c @@ -225,7 +225,7 @@ __relay_get_transaction(struct xe_guc_relay *relay, bool incoming, u32 remote, u * with CTB lock held which is marked as used in the reclaim path. * Btw, that's one of the reason why we use mempool here! */ - txn = mempool_alloc(&relay->pool, incoming ? GFP_ATOMIC : GFP_KERNEL); + txn = mempool_alloc(&relay->pool, incoming ? GFP_ATOMIC : GFP_NOWAIT); if (!txn) return ERR_PTR(-ENOMEM); From 459777724d306315070d24608fcd89aea85516d6 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Fri, 31 Jan 2025 19:25:02 +0100 Subject: [PATCH 087/130] drm/xe/vf: Don't try to trigger a full GT reset if VF VFs don't have access to the GDRST(0x941c) register that driver uses to reset a GT. Attempt to trigger a reset using debugfs: $ cat /sys/kernel/debug/dri/0000:00:02.1/gt0/force_reset or due to a hang condition detected by the driver leads to: [ ] xe 0000:00:02.1: [drm] GT0: trying reset from force_reset [xe] [ ] xe 0000:00:02.1: [drm] GT0: reset queued [ ] xe 0000:00:02.1: [drm] GT0: reset started [ ] ------------[ cut here ]------------ [ ] xe 0000:00:02.1: [drm] GT0: VF is trying to write 0x1 to an inaccessible register 0x941c+0x0 [ ] WARNING: CPU: 3 PID: 3069 at drivers/gpu/drm/xe/xe_gt_sriov_vf.c:996 xe_gt_sriov_vf_write32+0xc6/0x580 [xe] [ ] RIP: 0010:xe_gt_sriov_vf_write32+0xc6/0x580 [xe] [ ] Call Trace: [ ] [ ] ? show_regs+0x6c/0x80 [ ] ? __warn+0x93/0x1c0 [ ] ? xe_gt_sriov_vf_write32+0xc6/0x580 [xe] [ ] ? report_bug+0x182/0x1b0 [ ] ? handle_bug+0x6e/0xb0 [ ] ? exc_invalid_op+0x18/0x80 [ ] ? asm_exc_invalid_op+0x1b/0x20 [ ] ? xe_gt_sriov_vf_write32+0xc6/0x580 [xe] [ ] ? xe_gt_sriov_vf_write32+0xc6/0x580 [xe] [ ] ? xe_gt_tlb_invalidation_reset+0xef/0x110 [xe] [ ] ? __mutex_unlock_slowpath+0x41/0x2e0 [ ] xe_mmio_write32+0x64/0x150 [xe] [ ] do_gt_reset+0x2f/0xa0 [xe] [ ] gt_reset_worker+0x14e/0x1e0 [xe] [ ] process_one_work+0x21c/0x740 [ ] worker_thread+0x1db/0x3c0 Fix that by sending H2G VF_RESET(0x5507) action instead. Closes: https://gitlab.freedesktop.org/drm/xe/kernel/-/issues/4078 Signed-off-by: Michal Wajdeczko Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20250131182502.852-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt.c | 4 ++++ drivers/gpu/drm/xe/xe_gt_sriov_vf.c | 16 ++++++++++++++++ drivers/gpu/drm/xe/xe_gt_sriov_vf.h | 1 + 3 files changed, 21 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 01a4a852b8f43..9fb8f1e678dc8 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -32,6 +32,7 @@ #include "xe_gt_pagefault.h" #include "xe_gt_printk.h" #include "xe_gt_sriov_pf.h" +#include "xe_gt_sriov_vf.h" #include "xe_gt_sysfs.h" #include "xe_gt_tlb_invalidation.h" #include "xe_gt_topology.h" @@ -679,6 +680,9 @@ static int do_gt_reset(struct xe_gt *gt) { int err; + if (IS_SRIOV_VF(gt_to_xe(gt))) + return xe_gt_sriov_vf_reset(gt); + xe_gsc_wa_14015076503(gt, true); xe_mmio_write32(>->mmio, GDRST, GRDOM_FULL); diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c index 6671030439fd7..4831549da319a 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.c @@ -58,6 +58,22 @@ static int vf_reset_guc_state(struct xe_gt *gt) return err; } +/** + * xe_gt_sriov_vf_reset - Reset GuC VF internal state. + * @gt: the &xe_gt + * + * It requires functional `GuC MMIO based communication`_. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_gt_sriov_vf_reset(struct xe_gt *gt) +{ + if (!xe_device_uc_enabled(gt_to_xe(gt))) + return -ENODEV; + + return vf_reset_guc_state(gt); +} + static int guc_action_match_version(struct xe_guc *guc, u32 wanted_branch, u32 wanted_major, u32 wanted_minor, u32 *branch, u32 *major, u32 *minor, u32 *patch) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_vf.h b/drivers/gpu/drm/xe/xe_gt_sriov_vf.h index 912d208142616..ba6c5d74e326f 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_vf.h +++ b/drivers/gpu/drm/xe/xe_gt_sriov_vf.h @@ -12,6 +12,7 @@ struct drm_printer; struct xe_gt; struct xe_reg; +int xe_gt_sriov_vf_reset(struct xe_gt *gt); int xe_gt_sriov_vf_bootstrap(struct xe_gt *gt); int xe_gt_sriov_vf_query_config(struct xe_gt *gt); int xe_gt_sriov_vf_connect(struct xe_gt *gt); From 9c9dc9ba4a00510c624588d9860968b26803a2b8 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Mon, 3 Feb 2025 15:48:57 -0800 Subject: [PATCH 088/130] drm/xe/pxp: Fail the load if PXP fails to initialize The PXP implementation mimics the i915 approach of allowing the load to continue even if PXP init has failed. On Xe however we're taking an harder stance on boot error and only allowing the load to complete if everything is working, so update the code to fail if anything goes wrong during PXP init. While at it, update the return code in case of PXP not supported to be 0 instead of EOPNOTSUPP, to follow the standard of functions called by xe_device_probe where every non-zero value means failure. Suggested-by: Lucas De Marchi Signed-off-by: Daniele Ceraolo Spurio Cc: Lucas De Marchi Cc: John Harrison Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20250203234857.1419637-1-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_device.c | 4 ++-- drivers/gpu/drm/xe/xe_pxp.c | 20 ++++++++++++-------- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index f30f8f668dee2..c641c802d4fb6 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -864,8 +864,8 @@ int xe_device_probe(struct xe_device *xe) /* A PXP init failure is not fatal */ err = xe_pxp_init(xe); - if (err && err != -EOPNOTSUPP) - drm_err(&xe->drm, "PXP initialization failed: %pe\n", ERR_PTR(err)); + if (err) + goto err_fini_display; err = drm_dev_register(&xe->drm, 0); if (err) diff --git a/drivers/gpu/drm/xe/xe_pxp.c b/drivers/gpu/drm/xe/xe_pxp.c index 5e7a1688a771c..3cd3f83e86b00 100644 --- a/drivers/gpu/drm/xe/xe_pxp.c +++ b/drivers/gpu/drm/xe/xe_pxp.c @@ -372,8 +372,8 @@ static void pxp_fini(void *arg) * are performed asynchronously as part of the GSC init. PXP can only be used * after both this function and the async worker have completed. * - * Returns -EOPNOTSUPP if PXP is not supported, 0 if PXP initialization is - * successful, other errno value if there is an error during the init. + * Returns 0 if PXP is not supported or if PXP initialization is successful, + * other errno value if there is an error during the init. */ int xe_pxp_init(struct xe_device *xe) { @@ -382,26 +382,28 @@ int xe_pxp_init(struct xe_device *xe) int err; if (!xe_pxp_is_supported(xe)) - return -EOPNOTSUPP; + return 0; /* we only support PXP on single tile devices with a media GT */ if (xe->info.tile_count > 1 || !gt) - return -EOPNOTSUPP; + return 0; /* The GSCCS is required for submissions to the GSC FW */ if (!(gt->info.engine_mask & BIT(XE_HW_ENGINE_GSCCS0))) - return -EOPNOTSUPP; + return 0; /* PXP requires both GSC and HuC firmwares to be available */ if (!xe_uc_fw_is_loadable(>->uc.gsc.fw) || !xe_uc_fw_is_loadable(>->uc.huc.fw)) { drm_info(&xe->drm, "skipping PXP init due to missing FW dependencies"); - return -EOPNOTSUPP; + return 0; } pxp = drmm_kzalloc(&xe->drm, sizeof(struct xe_pxp), GFP_KERNEL); - if (!pxp) - return -ENOMEM; + if (!pxp) { + err = -ENOMEM; + goto out; + } INIT_LIST_HEAD(&pxp->queues.list); spin_lock_init(&pxp->queues.lock); @@ -448,6 +450,8 @@ int xe_pxp_init(struct xe_device *xe) destroy_workqueue(pxp->irq.wq); out_free: drmm_kfree(&xe->drm, pxp); +out: + drm_err(&xe->drm, "PXP initialization failed: %pe\n", ERR_PTR(err)); return err; } From dac328dea701ed1fde2b67176fe3c3a818536441 Mon Sep 17 00:00:00 2001 From: Raag Jadav Date: Fri, 31 Jan 2025 11:15:02 +0530 Subject: [PATCH 089/130] drm/xe/hwmon: expose package and vram temperature Add hwmon support for temp2_input and temp3_input attributes, which will expose package and vram temperature in millidegree Celsius. With this in place we can monitor temperature using lm-sensors tool. v2: Reuse existing channels (Badal, Karthik) Signed-off-by: Raag Jadav Reviewed-by: Andi Shyti Reviewed-by: Badal Nilawar Link: https://patchwork.freedesktop.org/patch/msgid/20250131054502.1528555-1-raag.jadav@intel.com Signed-off-by: Rodrigo Vivi --- .../ABI/testing/sysfs-driver-intel-xe-hwmon | 16 +++++ drivers/gpu/drm/xe/regs/xe_mchbar_regs.h | 3 + drivers/gpu/drm/xe/regs/xe_pcode_regs.h | 2 + drivers/gpu/drm/xe/xe_hwmon.c | 60 +++++++++++++++++++ 4 files changed, 81 insertions(+) diff --git a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon index d792a56f59acf..9bce281314dfd 100644 --- a/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon +++ b/Documentation/ABI/testing/sysfs-driver-intel-xe-hwmon @@ -108,3 +108,19 @@ Contact: intel-xe@lists.freedesktop.org Description: RO. Package current voltage in millivolt. Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp2_input +Date: March 2025 +KernelVersion: 6.14 +Contact: intel-xe@lists.freedesktop.org +Description: RO. Package temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. + +What: /sys/bus/pci/drivers/xe/.../hwmon/hwmon/temp3_input +Date: March 2025 +KernelVersion: 6.14 +Contact: intel-xe@lists.freedesktop.org +Description: RO. VRAM temperature in millidegree Celsius. + + Only supported for particular Intel Xe graphics platforms. diff --git a/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h b/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h index 519dd1067a198..f5e5234857c19 100644 --- a/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_mchbar_regs.h @@ -34,6 +34,9 @@ #define PCU_CR_PACKAGE_ENERGY_STATUS XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x593c) +#define PCU_CR_PACKAGE_TEMPERATURE XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x5978) +#define TEMP_MASK REG_GENMASK(7, 0) + #define PCU_CR_PACKAGE_RAPL_LIMIT XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x59a0) #define PKG_PWR_LIM_1 REG_GENMASK(14, 0) #define PKG_PWR_LIM_1_EN REG_BIT(15) diff --git a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h index 0b0b49d850aef..8846eb9ce2a40 100644 --- a/drivers/gpu/drm/xe/regs/xe_pcode_regs.h +++ b/drivers/gpu/drm/xe/regs/xe_pcode_regs.h @@ -21,6 +21,8 @@ #define BMG_PACKAGE_POWER_SKU XE_REG(0x138098) #define BMG_PACKAGE_POWER_SKU_UNIT XE_REG(0x1380dc) #define BMG_PACKAGE_ENERGY_STATUS XE_REG(0x138120) +#define BMG_VRAM_TEMPERATURE XE_REG(0x1382c0) +#define BMG_PACKAGE_TEMPERATURE XE_REG(0x138434) #define BMG_PACKAGE_RAPL_LIMIT XE_REG(0x138440) #define BMG_PLATFORM_ENERGY_STATUS XE_REG(0x138458) #define BMG_PLATFORM_POWER_LIMIT XE_REG(0x138460) diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index fde56dad3ab7a..7f327e3342123 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -6,6 +6,7 @@ #include #include #include +#include #include #include "regs/xe_gt_regs.h" @@ -20,6 +21,7 @@ #include "xe_pm.h" enum xe_hwmon_reg { + REG_TEMP, REG_PKG_RAPL_LIMIT, REG_PKG_POWER_SKU, REG_PKG_POWER_SKU_UNIT, @@ -36,6 +38,7 @@ enum xe_hwmon_reg_operation { enum xe_hwmon_channel { CHANNEL_CARD, CHANNEL_PKG, + CHANNEL_VRAM, CHANNEL_MAX, }; @@ -84,6 +87,19 @@ static struct xe_reg xe_hwmon_get_reg(struct xe_hwmon *hwmon, enum xe_hwmon_reg struct xe_device *xe = hwmon->xe; switch (hwmon_reg) { + case REG_TEMP: + if (xe->info.platform == XE_BATTLEMAGE) { + if (channel == CHANNEL_PKG) + return BMG_PACKAGE_TEMPERATURE; + else if (channel == CHANNEL_VRAM) + return BMG_VRAM_TEMPERATURE; + } else if (xe->info.platform == XE_DG2) { + if (channel == CHANNEL_PKG) + return PCU_CR_PACKAGE_TEMPERATURE; + else if (channel == CHANNEL_VRAM) + return BMG_VRAM_TEMPERATURE; + } + break; case REG_PKG_RAPL_LIMIT: if (xe->info.platform == XE_BATTLEMAGE) { if (channel == CHANNEL_PKG) @@ -431,6 +447,8 @@ 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(power, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_LABEL, HWMON_P_MAX | HWMON_P_RATED_MAX | HWMON_P_CRIT | HWMON_P_LABEL), HWMON_CHANNEL_INFO(curr, HWMON_C_LABEL, HWMON_C_CRIT | HWMON_C_LABEL), @@ -506,6 +524,36 @@ 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 umode_t +xe_hwmon_temp_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) +{ + switch (attr) { + case hwmon_temp_input: + case hwmon_temp_label: + return xe_reg_is_valid(xe_hwmon_get_reg(hwmon, REG_TEMP, channel)) ? 0444 : 0; + default: + return 0; + } +} + +static int +xe_hwmon_temp_read(struct xe_hwmon *hwmon, u32 attr, int channel, long *val) +{ + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); + u64 reg_val; + + switch (attr) { + case hwmon_temp_input: + 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; + default: + return -EOPNOTSUPP; + } +} + static umode_t xe_hwmon_power_is_visible(struct xe_hwmon *hwmon, u32 attr, int channel) { @@ -667,6 +715,9 @@ xe_hwmon_is_visible(const void *drvdata, enum hwmon_sensor_types type, xe_pm_runtime_get(hwmon->xe); switch (type) { + case hwmon_temp: + ret = xe_hwmon_temp_is_visible(hwmon, attr, channel); + break; case hwmon_power: ret = xe_hwmon_power_is_visible(hwmon, attr, channel); break; @@ -699,6 +750,9 @@ xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, xe_pm_runtime_get(hwmon->xe); switch (type) { + case hwmon_temp: + ret = xe_hwmon_temp_read(hwmon, attr, channel, val); + break; case hwmon_power: ret = xe_hwmon_power_read(hwmon, attr, channel, val); break; @@ -752,6 +806,12 @@ static int xe_hwmon_read_label(struct device *dev, u32 attr, int channel, const char **str) { switch (type) { + case hwmon_temp: + if (channel == CHANNEL_PKG) + *str = "pkg"; + else if (channel == CHANNEL_VRAM) + *str = "vram"; + return 0; case hwmon_power: case hwmon_energy: case hwmon_curr: From 8a734b9359cfa1bdb805f5ca23e20bd99dd18a0a Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Thu, 9 Jan 2025 14:52:19 -0500 Subject: [PATCH 090/130] drm/xe: Fix PVC RPe and RPa information A simple lazy buggy copy and paste of the PVC comment has brought the attention to the incorrect masks of the PVC register for RPa and RPe. So, let's fix them all. Cc: Lucas De Marchi Cc: Vinay Belgaumkar Reviewed-by: Vinay Belgaumkar Link: https://patchwork.freedesktop.org/patch/msgid/20250109195219.658557-1-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_guc_pc.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_guc_pc.c b/drivers/gpu/drm/xe/xe_guc_pc.c index 43f9617baba29..02409eedb9143 100644 --- a/drivers/gpu/drm/xe/xe_guc_pc.c +++ b/drivers/gpu/drm/xe/xe_guc_pc.c @@ -363,16 +363,17 @@ static void tgl_update_rpa_value(struct xe_guc_pc *pc) u32 reg; /* - * For PVC we still need to use fused RP1 as the approximation for RPe - * For other platforms than PVC we get the resolved RPe directly from + * For PVC we still need to use fused RP0 as the approximation for RPa + * For other platforms than PVC we get the resolved RPa directly from * PCODE at a different register */ - if (xe->info.platform == XE_PVC) + if (xe->info.platform == XE_PVC) { reg = xe_mmio_read32(>->mmio, PVC_RP_STATE_CAP); - else + pc->rpa_freq = REG_FIELD_GET(RP0_MASK, reg) * GT_FREQUENCY_MULTIPLIER; + } else { reg = xe_mmio_read32(>->mmio, FREQ_INFO_REC); - - pc->rpa_freq = REG_FIELD_GET(RPA_MASK, reg) * GT_FREQUENCY_MULTIPLIER; + pc->rpa_freq = REG_FIELD_GET(RPA_MASK, reg) * GT_FREQUENCY_MULTIPLIER; + } } static void tgl_update_rpe_value(struct xe_guc_pc *pc) @@ -386,12 +387,13 @@ static void tgl_update_rpe_value(struct xe_guc_pc *pc) * For other platforms than PVC we get the resolved RPe directly from * PCODE at a different register */ - if (xe->info.platform == XE_PVC) + if (xe->info.platform == XE_PVC) { reg = xe_mmio_read32(>->mmio, PVC_RP_STATE_CAP); - else + pc->rpe_freq = REG_FIELD_GET(RP1_MASK, reg) * GT_FREQUENCY_MULTIPLIER; + } else { reg = xe_mmio_read32(>->mmio, FREQ_INFO_REC); - - pc->rpe_freq = REG_FIELD_GET(RPE_MASK, reg) * GT_FREQUENCY_MULTIPLIER; + pc->rpe_freq = REG_FIELD_GET(RPE_MASK, reg) * GT_FREQUENCY_MULTIPLIER; + } } static void pc_update_rp_values(struct xe_guc_pc *pc) From 01aebfaeff324d21f559a696016e13640f59b297 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Wed, 5 Feb 2025 13:01:50 +0100 Subject: [PATCH 091/130] drm/xe: Don't treat SR-IOV platforms as reclaim unsafe MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since commit a4d1c5d0b99b ("drm/xe/pf: Move VFs reprovisioning to worker") and commit 78d5d1e20d1d ("drm/xe/relay: Don't use GFP_KERNEL for new transactions") we should have no more lockdep dependencies on the reclaim path when running in the SRIOV mode so we believe that we can now mark SRIOV driver as reclaim safe. Signed-off-by: Michal Wajdeczko Cc: Thomas Hellström Cc: Jonathan Cavitt Cc: Matthew Brost Tested-by: Marcin Bernatowicz Reviewed-by: Marcin Bernatowicz Reviewed-by: Thomas Hellström Link: https://patchwork.freedesktop.org/patch/msgid/20250205120150.896-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_pm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_pm.c b/drivers/gpu/drm/xe/xe_pm.c index 35dd1757b40be..12200be7b43df 100644 --- a/drivers/gpu/drm/xe/xe_pm.c +++ b/drivers/gpu/drm/xe/xe_pm.c @@ -91,7 +91,7 @@ static struct lockdep_map xe_pm_runtime_nod3cold_map = { */ bool xe_rpm_reclaim_safe(const struct xe_device *xe) { - return !xe->d3cold.capable && !xe->info.has_sriov; + return !xe->d3cold.capable; } static void xe_rpm_lockmap_acquire(const struct xe_device *xe) From 5b380838930f1fb74d38f34ca4bff43416db01c3 Mon Sep 17 00:00:00 2001 From: Francois Dugast Date: Thu, 6 Feb 2025 14:45:50 +0100 Subject: [PATCH 092/130] drm/xe: Add stats for vma page faults Add new entries in stats for vma page faults. If CONFIG_DEBUG_FS is enabled, the count and number of bytes can be viewed per GT in the stat debugfs file. This helps when testing, to confirm page faults have been triggered as expected. It also helps when looking at the performance impact of page faults. Data is simply collected when entering the page fault handler so there is no indication whether it completed successfully, with or without retries, etc. Example output: cat /sys/kernel/debug/dri/0/gt0/stats tlb_inval_count: 129 vma_pagefault_count: 12 vma_pagefault_bytes: 98304 v2: Rebase Reviewed-by: Jonathan Cavitt Link: https://patchwork.freedesktop.org/patch/msgid/20250206134551.1321265-1-francois.dugast@intel.com Signed-off-by: Francois Dugast --- drivers/gpu/drm/xe/xe_gt_pagefault.c | 10 +++++++--- drivers/gpu/drm/xe/xe_gt_stats.c | 2 ++ drivers/gpu/drm/xe/xe_gt_stats_types.h | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt_pagefault.c b/drivers/gpu/drm/xe/xe_gt_pagefault.c index cb92fb5cbc759..46701ca11ce0d 100644 --- a/drivers/gpu/drm/xe/xe_gt_pagefault.c +++ b/drivers/gpu/drm/xe/xe_gt_pagefault.c @@ -14,6 +14,7 @@ #include "abi/guc_actions_abi.h" #include "xe_bo.h" #include "xe_gt.h" +#include "xe_gt_stats.h" #include "xe_gt_tlb_invalidation.h" #include "xe_guc.h" #include "xe_guc_ct.h" @@ -124,16 +125,20 @@ static int xe_pf_begin(struct drm_exec *exec, struct xe_vma *vma, return 0; } -static int handle_vma_pagefault(struct xe_tile *tile, struct pagefault *pf, +static int handle_vma_pagefault(struct xe_gt *gt, struct pagefault *pf, struct xe_vma *vma) { struct xe_vm *vm = xe_vma_vm(vma); + struct xe_tile *tile = gt_to_tile(gt); struct drm_exec exec; struct dma_fence *fence; ktime_t end = 0; int err; bool atomic; + xe_gt_stats_incr(gt, XE_GT_STATS_ID_VMA_PAGEFAULT_COUNT, 1); + xe_gt_stats_incr(gt, XE_GT_STATS_ID_VMA_PAGEFAULT_BYTES, xe_vma_size(vma)); + trace_xe_vma_pagefault(vma); atomic = access_is_atomic(pf->access_type); @@ -202,7 +207,6 @@ static struct xe_vm *asid_to_vm(struct xe_device *xe, u32 asid) static int handle_pagefault(struct xe_gt *gt, struct pagefault *pf) { struct xe_device *xe = gt_to_xe(gt); - struct xe_tile *tile = gt_to_tile(gt); struct xe_vm *vm; struct xe_vma *vma = NULL; int err; @@ -231,7 +235,7 @@ static int handle_pagefault(struct xe_gt *gt, struct pagefault *pf) goto unlock_vm; } - err = handle_vma_pagefault(tile, pf, vma); + err = handle_vma_pagefault(gt, pf, vma); unlock_vm: if (!err) diff --git a/drivers/gpu/drm/xe/xe_gt_stats.c b/drivers/gpu/drm/xe/xe_gt_stats.c index 7a6c1d808e419..2e9879ea4674a 100644 --- a/drivers/gpu/drm/xe/xe_gt_stats.c +++ b/drivers/gpu/drm/xe/xe_gt_stats.c @@ -28,6 +28,8 @@ void xe_gt_stats_incr(struct xe_gt *gt, const enum xe_gt_stats_id id, int incr) static const char *const stat_description[__XE_GT_STATS_NUM_IDS] = { "tlb_inval_count", + "vma_pagefault_count", + "vma_pagefault_bytes", }; /** diff --git a/drivers/gpu/drm/xe/xe_gt_stats_types.h b/drivers/gpu/drm/xe/xe_gt_stats_types.h index 2fc055e39f273..b072bd80c4b97 100644 --- a/drivers/gpu/drm/xe/xe_gt_stats_types.h +++ b/drivers/gpu/drm/xe/xe_gt_stats_types.h @@ -8,6 +8,8 @@ enum xe_gt_stats_id { XE_GT_STATS_ID_TLB_INVAL, + XE_GT_STATS_ID_VMA_PAGEFAULT_COUNT, + XE_GT_STATS_ID_VMA_PAGEFAULT_BYTES, /* must be the last entry */ __XE_GT_STATS_NUM_IDS, }; From 6bb05b3631bd81227298b291b651dc7ec6ee0145 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Thu, 6 Feb 2025 22:45:45 +0100 Subject: [PATCH 093/130] drm/xe: Enable SR-IOV for PTL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We should now have sufficient changes in the driver to run it on PTL platforms in the SR-IOV Physical Function (PF) mode, that would allow us to enable SR-IOV Virtual Functions (VFs), and successfully probe our driver in the VF mode on enabled VF devices. To unblock SR-IOV PF mode you need to load xe with modparam: xe.max_vfs=7 Then to enable VFs it is sufficient to use: $ echo 7 > /sys/bus/pci/devices/0000:00:02.0/sriov_numvfs Note that in default auto-provisioning all VFs are allocated with some amount of shared resources (like unlimited GPU execution and preemption times, fair GGTT space, fair GuC context IDs range, ...) However with CONFIG_DEBUG_FS enabled it is possible to tweak most of the SR-IOV configuration parameters using attributes like: /sys/kernel/debug/dri/0000:00:02.0/gt0/ ├── pf │   ├── contexts_spare │   ├── doorbells_spare │   ├── exec_quantum_ms │   ├── ggtt_spare │   ├── preempt_timeout_us │   ├── sched_priority │   └── ... ├── vf1 │   ├── contexts_quota │   ├── doorbells_quota │   ├── exec_quantum_ms │   ├── ggtt_quota │   ├── preempt_timeout_us │   ├── sched_priority │   └── ... ├── vf2 │   └── ... : Signed-off-by: Michal Wajdeczko Cc: Rodrigo Vivi Cc: Lucas De Marchi Cc: Thomas Hellstrom Acked-by: Rodrigo Vivi Reviewed-by: Jakub Kolakowski Tested-by: Marcin Bernatowicz Reviewed-by: Marcin Bernatowicz Link: https://patchwork.freedesktop.org/patch/msgid/20250206214545.940-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_pci.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index cfa1ad7a1f2d3..663bfc29cddc1 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -363,6 +363,7 @@ static const struct xe_device_desc ptl_desc = { PLATFORM(PANTHERLAKE), .dma_mask_size = 46, .has_display = true, + .has_sriov = true, .require_force_probe = true, }; From cbc0a0ee34b5f108b184a6d59afd0f305564350a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pi=C3=B3rkowski?= Date: Fri, 7 Feb 2025 12:31:11 +0100 Subject: [PATCH 094/130] drm/xe/pf: Use an explicit check to see if the device has LMTT MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit So far, the main condition for using LMTT has been to check that the device is a discrete gfx. Let's add a dedicated function to check if the device supports LMTT as not all future discrete GPU platforms will require LMTT. v2: - use xe_has_device_lmtt only when necessary - leave IS_DGFX for other things related to LMEM provisioning v3: - remove IS_SRIOV_PF condition from xe_device_has_lmtt (Michal Wajdeczko) - keep IS_SRIOV_PF asserts in LMTT-related code (Michal Wajdeczko) v4: - update commit description Signed-off-by: Piotr Piórkowski Cc: Michal Wajdeczko Cc: Michał Winiarski Cc: Satyanarayana K V P Reviewed-by: Tejas Upadhyay Reviewed-by: Satyanarayana K V P Signed-off-by: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/20250207113111.853821-2-piotr.piorkowski@intel.com --- drivers/gpu/drm/xe/xe_device.h | 5 +++++ drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 21 +++++++++++++-------- drivers/gpu/drm/xe/xe_lmtt.c | 4 ++-- 3 files changed, 20 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h index fc3c2af3fb7fd..0bc3bc8e68030 100644 --- a/drivers/gpu/drm/xe/xe_device.h +++ b/drivers/gpu/drm/xe/xe_device.h @@ -170,6 +170,11 @@ static inline bool xe_device_uses_memirq(struct xe_device *xe) return xe_device_has_memirq(xe) && (IS_SRIOV_VF(xe) || xe_device_has_msix(xe)); } +static inline bool xe_device_has_lmtt(struct xe_device *xe) +{ + return IS_DGFX(xe); +} + u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size); void xe_device_snapshot_print(struct xe_device *xe, struct drm_printer *p); diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index b1d994d655896..5c3e9e5bd0519 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -1336,7 +1336,7 @@ static void pf_reset_vf_lmtt(struct xe_device *xe, unsigned int vfid) struct xe_tile *tile; unsigned int tid; - xe_assert(xe, IS_DGFX(xe)); + xe_assert(xe, xe_device_has_lmtt(xe)); xe_assert(xe, IS_SRIOV_PF(xe)); for_each_tile(tile, xe, tid) { @@ -1357,7 +1357,7 @@ static int pf_update_vf_lmtt(struct xe_device *xe, unsigned int vfid) unsigned int tid; int err; - xe_assert(xe, IS_DGFX(xe)); + xe_assert(xe, xe_device_has_lmtt(xe)); xe_assert(xe, IS_SRIOV_PF(xe)); total = 0; @@ -1434,7 +1434,8 @@ static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size) if (unlikely(err)) return err; - pf_reset_vf_lmtt(xe, vfid); + if (xe_device_has_lmtt(xe)) + pf_reset_vf_lmtt(xe, vfid); pf_release_vf_config_lmem(gt, config); } xe_gt_assert(gt, !config->lmem_obj); @@ -1454,9 +1455,11 @@ static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size) config->lmem_obj = bo; - err = pf_update_vf_lmtt(xe, vfid); - if (unlikely(err)) - goto release; + if (xe_device_has_lmtt(xe)) { + err = pf_update_vf_lmtt(xe, vfid); + if (unlikely(err)) + goto release; + } err = pf_push_vf_cfg_lmem(gt, vfid, bo->size); if (unlikely(err)) @@ -1467,7 +1470,8 @@ static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size) return 0; reset_lmtt: - pf_reset_vf_lmtt(xe, vfid); + if (xe_device_has_lmtt(xe)) + pf_reset_vf_lmtt(xe, vfid); release: pf_release_vf_config_lmem(gt, config); return err; @@ -1981,7 +1985,8 @@ static void pf_release_vf_config(struct xe_gt *gt, unsigned int vfid) pf_release_vf_config_ggtt(gt, config); if (IS_DGFX(xe)) { pf_release_vf_config_lmem(gt, config); - pf_update_vf_lmtt(xe, vfid); + if (xe_device_has_lmtt(xe)) + pf_update_vf_lmtt(xe, vfid); } } pf_release_config_ctxs(gt, config); diff --git a/drivers/gpu/drm/xe/xe_lmtt.c b/drivers/gpu/drm/xe/xe_lmtt.c index a60ceae4c6dd2..89393dcb53d9d 100644 --- a/drivers/gpu/drm/xe/xe_lmtt.c +++ b/drivers/gpu/drm/xe/xe_lmtt.c @@ -164,7 +164,7 @@ int xe_lmtt_init(struct xe_lmtt *lmtt) lmtt_assert(lmtt, IS_SRIOV_PF(xe)); lmtt_assert(lmtt, !lmtt->ops); - if (!IS_DGFX(xe)) + if (!xe_device_has_lmtt(xe)) return 0; if (xe_has_multi_level_lmtt(xe)) @@ -486,7 +486,7 @@ u64 xe_lmtt_estimate_pt_size(struct xe_lmtt *lmtt, u64 size) u64 pt_size; lmtt_assert(lmtt, IS_SRIOV_PF(lmtt_to_xe(lmtt))); - lmtt_assert(lmtt, IS_DGFX(lmtt_to_xe(lmtt))); + lmtt_assert(lmtt, xe_device_has_lmtt(lmtt_to_xe(lmtt))); lmtt_assert(lmtt, lmtt->ops); pt_size = PAGE_ALIGN(lmtt->ops->lmtt_pte_size(level) * From fc3a50c12ebd33c77b7e4a1e4f154a44315d3169 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pi=C3=B3rkowski?= Date: Mon, 10 Feb 2025 09:15:10 +0100 Subject: [PATCH 095/130] drm/xe: Rename struct xe_mem_region to struct xe_vram_region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The xe_mem_region structure has so far been used only in the context of VRAM regions. Also, the description of its fields clearly indicates that it was designed for VRAM regions. This struct is strictly related only to VRAM. So let's be clear on this point and rename it to xe_vram_region. Signed-off-by: Piotr Piórkowski Reviewed-by: Rodrigo Vivi Signed-off-by: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/20250210081511.906452-2-piotr.piorkowski@intel.com --- drivers/gpu/drm/xe/xe_bo.c | 12 ++++++------ drivers/gpu/drm/xe/xe_device_types.h | 8 ++++---- drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 2 +- drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 6812164e1470a..a202d55258225 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -143,7 +143,7 @@ mem_type_to_migrate(struct xe_device *xe, u32 mem_type) return tile->migrate; } -static struct xe_mem_region *res_to_mem_region(struct ttm_resource *res) +static struct xe_vram_region *res_to_mem_region(struct ttm_resource *res) { struct xe_device *xe = ttm_to_xe_device(res->bo->bdev); struct ttm_resource_manager *mgr; @@ -179,7 +179,7 @@ static void add_vram(struct xe_device *xe, struct xe_bo *bo, struct ttm_place *places, u32 bo_flags, u32 mem_type, u32 *c) { struct ttm_place place = { .mem_type = mem_type }; - struct xe_mem_region *vram; + struct xe_vram_region *vram; u64 io_size; xe_assert(xe, *c < ARRAY_SIZE(bo->placements)); @@ -468,7 +468,7 @@ static int xe_ttm_io_mem_reserve(struct ttm_device *bdev, return 0; case XE_PL_VRAM0: case XE_PL_VRAM1: { - struct xe_mem_region *vram = res_to_mem_region(mem); + struct xe_vram_region *vram = res_to_mem_region(mem); if (!xe_ttm_resource_visible(mem)) return -EINVAL; @@ -815,7 +815,7 @@ static int xe_bo_move(struct ttm_buffer_object *ttm_bo, bool evict, /* Create a new VMAP once kernel BO back in VRAM */ if (!ret && resource_is_vram(new_mem)) { - struct xe_mem_region *vram = res_to_mem_region(new_mem); + struct xe_vram_region *vram = res_to_mem_region(new_mem); void __iomem *new_addr = vram->mapping + (new_mem->start << PAGE_SHIFT); @@ -1025,7 +1025,7 @@ static unsigned long xe_ttm_io_mem_pfn(struct ttm_buffer_object *ttm_bo, { struct xe_bo *bo = ttm_to_xe_bo(ttm_bo); struct xe_res_cursor cursor; - struct xe_mem_region *vram; + struct xe_vram_region *vram; if (ttm_bo->resource->mem_type == XE_PL_STOLEN) return xe_ttm_stolen_io_offset(bo, page_offset << PAGE_SHIFT) >> PAGE_SHIFT; @@ -1165,7 +1165,7 @@ static int xe_ttm_access_memory(struct ttm_buffer_object *ttm_bo, struct xe_device *xe = ttm_to_xe_device(ttm_bo->bdev); struct iosys_map vmap; struct xe_res_cursor cursor; - struct xe_mem_region *vram; + struct xe_vram_region *vram; int bytes_left = len; xe_bo_assert_held(bo); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index c0e886bac1831..1f27ed2c0448c 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -70,11 +70,11 @@ struct xe_pxp; struct xe_tile * : (tile__)->xe) /** - * struct xe_mem_region - memory region structure + * struct xe_vram_region - memory region structure * This is used to describe a memory region in xe * device, such as HBM memory or CXL extension memory. */ -struct xe_mem_region { +struct xe_vram_region { /** @io_start: IO start address of this VRAM instance */ resource_size_t io_start; /** @@ -197,7 +197,7 @@ struct xe_tile { * Although VRAM is associated with a specific tile, it can * still be accessed by all tiles' GTs. */ - struct xe_mem_region vram; + struct xe_vram_region vram; /** @mem.vram_mgr: VRAM TTM manager */ struct xe_ttm_vram_mgr *vram_mgr; @@ -369,7 +369,7 @@ struct xe_device { /** @mem: memory info for device */ struct { /** @mem.vram: VRAM info for device */ - struct xe_mem_region vram; + struct xe_vram_region vram; /** @mem.sys_mgr: system TTM manager */ struct ttm_resource_manager sys_mgr; } mem; diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c index f4a16e5fa7700..a8c37fb4fec08 100644 --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c @@ -340,7 +340,7 @@ int __xe_ttm_vram_mgr_init(struct xe_device *xe, struct xe_ttm_vram_mgr *mgr, int xe_ttm_vram_mgr_init(struct xe_tile *tile, struct xe_ttm_vram_mgr *mgr) { struct xe_device *xe = tile_to_xe(tile); - struct xe_mem_region *vram = &tile->mem.vram; + struct xe_vram_region *vram = &tile->mem.vram; mgr->vram = vram; return __xe_ttm_vram_mgr_init(xe, mgr, XE_PL_VRAM0 + tile->id, diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h b/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h index 2d75cf1262893..4c52ced4ee447 100644 --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h @@ -9,7 +9,7 @@ #include #include -struct xe_mem_region; +struct xe_vram_region; /** * struct xe_ttm_vram_mgr - XE TTM VRAM manager @@ -22,7 +22,7 @@ struct xe_ttm_vram_mgr { /** @mm: DRM buddy allocator which manages the VRAM */ struct drm_buddy mm; /** @vram: ptr to details of associated VRAM region */ - struct xe_mem_region *vram; + struct xe_vram_region *vram; /** @visible_size: Proped size of the CPU visible portion */ u64 visible_size; /** @visible_avail: CPU visible portion still unallocated */ From 71163271dc227f8dd0d9446b8897a141c2eae957 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Pi=C3=B3rkowski?= Date: Mon, 10 Feb 2025 09:15:11 +0100 Subject: [PATCH 096/130] drm/xe: Move VRAM manager to struct xe_vram_region MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit VRAM manager is related directly to struct xe_vram_region so it should be inside this structure. Let's move the VRAM to struct xe_vram_region. v2: - remove xe_vram_region pointer from xe_ttm_vram_mgr - stop use dynamic alloaction for xe_ttm_vram_mgr in xe_vram_region - rename struct xe_ttm_vram_mgr vram_mgr to ttm v3: - fix "'ttm' not described in 'xe_vram_region'" Signed-off-by: Piotr Piórkowski Cc: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Signed-off-by: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/20250210081511.906452-3-piotr.piorkowski@intel.com --- drivers/gpu/drm/xe/xe_bo.c | 10 ++++++++-- drivers/gpu/drm/xe/xe_device_types.h | 6 +++--- drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 2 +- drivers/gpu/drm/xe/xe_tile.c | 6 +----- drivers/gpu/drm/xe/xe_ttm_vram_mgr.c | 1 - drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h | 4 ---- 6 files changed, 13 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index a202d55258225..78d09c5ed26d1 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -147,10 +147,13 @@ static struct xe_vram_region *res_to_mem_region(struct ttm_resource *res) { struct xe_device *xe = ttm_to_xe_device(res->bo->bdev); struct ttm_resource_manager *mgr; + struct xe_ttm_vram_mgr *vram_mgr; xe_assert(xe, resource_is_vram(res)); mgr = ttm_manager_type(&xe->ttm, res->mem_type); - return to_xe_ttm_vram_mgr(mgr)->vram; + vram_mgr = to_xe_ttm_vram_mgr(mgr); + + return container_of(vram_mgr, struct xe_vram_region, ttm); } static void try_add_system(struct xe_device *xe, struct xe_bo *bo, @@ -179,12 +182,15 @@ static void add_vram(struct xe_device *xe, struct xe_bo *bo, struct ttm_place *places, u32 bo_flags, u32 mem_type, u32 *c) { struct ttm_place place = { .mem_type = mem_type }; + struct ttm_resource_manager *mgr = ttm_manager_type(&xe->ttm, mem_type); + struct xe_ttm_vram_mgr *vram_mgr = to_xe_ttm_vram_mgr(mgr); + struct xe_vram_region *vram; u64 io_size; xe_assert(xe, *c < ARRAY_SIZE(bo->placements)); - vram = to_xe_ttm_vram_mgr(ttm_manager_type(&xe->ttm, mem_type))->vram; + vram = container_of(vram_mgr, struct xe_vram_region, ttm); xe_assert(xe, vram && vram->usable_size); io_size = vram->io_size; diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 1f27ed2c0448c..28d10a1d7b649 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -23,6 +23,7 @@ #include "xe_sriov_types.h" #include "xe_step_types.h" #include "xe_survivability_mode_types.h" +#include "xe_ttm_vram_mgr_types.h" #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) #define TEST_VM_OPS_ERROR @@ -105,6 +106,8 @@ struct xe_vram_region { resource_size_t actual_physical_size; /** @mapping: pointer to VRAM mappable space */ void __iomem *mapping; + /** @ttm: VRAM TTM manager */ + struct xe_ttm_vram_mgr ttm; }; /** @@ -199,9 +202,6 @@ struct xe_tile { */ struct xe_vram_region vram; - /** @mem.vram_mgr: VRAM TTM manager */ - struct xe_ttm_vram_mgr *vram_mgr; - /** @mem.ggtt: Global graphics translation table */ struct xe_ggtt *ggtt; diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index 5c3e9e5bd0519..88bd9d97ba5ca 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -1564,7 +1564,7 @@ static u64 pf_query_free_lmem(struct xe_gt *gt) { struct xe_tile *tile = gt->tile; - return xe_ttm_vram_get_avail(&tile->mem.vram_mgr->manager); + return xe_ttm_vram_get_avail(&tile->mem.vram.ttm.manager); } static u64 pf_query_max_lmem(struct xe_gt *gt) diff --git a/drivers/gpu/drm/xe/xe_tile.c b/drivers/gpu/drm/xe/xe_tile.c index 2825553b568f7..d9a7a04ff652f 100644 --- a/drivers/gpu/drm/xe/xe_tile.c +++ b/drivers/gpu/drm/xe/xe_tile.c @@ -94,10 +94,6 @@ static int xe_tile_alloc(struct xe_tile *tile) return -ENOMEM; tile->mem.ggtt->tile = tile; - tile->mem.vram_mgr = drmm_kzalloc(drm, sizeof(*tile->mem.vram_mgr), GFP_KERNEL); - if (!tile->mem.vram_mgr) - return -ENOMEM; - return 0; } @@ -139,7 +135,7 @@ static int tile_ttm_mgr_init(struct xe_tile *tile) int err; if (tile->mem.vram.usable_size) { - err = xe_ttm_vram_mgr_init(tile, tile->mem.vram_mgr); + err = xe_ttm_vram_mgr_init(tile, &tile->mem.vram.ttm); if (err) return err; xe->info.mem_region_mask |= BIT(tile->id) << 1; diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c index a8c37fb4fec08..9e375a40aee90 100644 --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr.c @@ -342,7 +342,6 @@ int xe_ttm_vram_mgr_init(struct xe_tile *tile, struct xe_ttm_vram_mgr *mgr) struct xe_device *xe = tile_to_xe(tile); struct xe_vram_region *vram = &tile->mem.vram; - mgr->vram = vram; return __xe_ttm_vram_mgr_init(xe, mgr, XE_PL_VRAM0 + tile->id, vram->usable_size, vram->io_size, PAGE_SIZE); diff --git a/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h b/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h index 4c52ced4ee447..1144f9232ebbb 100644 --- a/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h +++ b/drivers/gpu/drm/xe/xe_ttm_vram_mgr_types.h @@ -9,8 +9,6 @@ #include #include -struct xe_vram_region; - /** * struct xe_ttm_vram_mgr - XE TTM VRAM manager * @@ -21,8 +19,6 @@ struct xe_ttm_vram_mgr { struct ttm_resource_manager manager; /** @mm: DRM buddy allocator which manages the VRAM */ struct drm_buddy mm; - /** @vram: ptr to details of associated VRAM region */ - struct xe_vram_region *vram; /** @visible_size: Proped size of the CPU visible portion */ u64 visible_size; /** @visible_avail: CPU visible portion still unallocated */ From f74fd53ba34551b7626193fb70c17226f06e9bf1 Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Wed, 5 Feb 2025 10:40:42 +0530 Subject: [PATCH 097/130] drm/xe/client: bo->client does not need bos_lock bos_lock is to protect list of bos used by client, it is not required to protect bo->client so bring it outside of bos_lock. Fixes: b27970f3e11c ("drm/xe: Add tracking support for bos per client") Signed-off-by: Tejas Upadhyay Reviewed-by: Himal Prasad Ghimiray Reviewed-by: Nirmoy Das Link: https://patchwork.freedesktop.org/patch/msgid/20250205051042.1991192-1-tejas.upadhyay@intel.com Signed-off-by: Nirmoy Das --- drivers/gpu/drm/xe/xe_drm_client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_drm_client.c b/drivers/gpu/drm/xe/xe_drm_client.c index 63f30b6df70b9..2d4874d2b9225 100644 --- a/drivers/gpu/drm/xe/xe_drm_client.c +++ b/drivers/gpu/drm/xe/xe_drm_client.c @@ -135,8 +135,8 @@ void xe_drm_client_add_bo(struct xe_drm_client *client, XE_WARN_ON(bo->client); XE_WARN_ON(!list_empty(&bo->client_link)); - spin_lock(&client->bos_lock); bo->client = xe_drm_client_get(client); + spin_lock(&client->bos_lock); list_add_tail(&bo->client_link, &client->bos_list); spin_unlock(&client->bos_lock); } From 2c7f45cc7e197a792ce5c693e56ea48f60b312da Mon Sep 17 00:00:00 2001 From: Nirmoy Das Date: Mon, 10 Feb 2025 15:36:54 +0100 Subject: [PATCH 098/130] drm/xe: Carve out wopcm portion from the stolen memory The top of stolen memory is WOPCM, which shouldn't be accessed. Remove this portion from the stolen memory region for discrete platforms. This was already done for integrated, but was missing for discrete platforms. This also moves get_wopcm_size() so detect_bar2_dgfx() and detect_bar2_integrated can use the same function. v2: Improve commit message and suitable stable version tag(Lucas) Fixes: d8b52a02cb40 ("drm/xe: Implement stolen memory.") Cc: Maarten Lankhorst Cc: Matthew Auld Cc: Lucas De Marchi Cc: stable@vger.kernel.org # v6.11+ Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20250210143654.2076747-1-nirmoy.das@intel.com Signed-off-by: Nirmoy Das --- drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c | 54 ++++++++++++++------------ 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c index 423856cc18d40..d414421f8c131 100644 --- a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c @@ -57,12 +57,35 @@ bool xe_ttm_stolen_cpu_access_needs_ggtt(struct xe_device *xe) return GRAPHICS_VERx100(xe) < 1270 && !IS_DGFX(xe); } +static u32 get_wopcm_size(struct xe_device *xe) +{ + u32 wopcm_size; + u64 val; + + val = xe_mmio_read64_2x32(xe_root_tile_mmio(xe), STOLEN_RESERVED); + val = REG_FIELD_GET64(WOPCM_SIZE_MASK, val); + + switch (val) { + case 0x5 ... 0x6: + val--; + fallthrough; + case 0x0 ... 0x3: + wopcm_size = (1U << val) * SZ_1M; + break; + default: + WARN(1, "Missing case wopcm_size=%llx\n", val); + wopcm_size = 0; + } + + return wopcm_size; +} + static s64 detect_bar2_dgfx(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr) { struct xe_tile *tile = xe_device_get_root_tile(xe); struct xe_mmio *mmio = xe_root_tile_mmio(xe); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); - u64 stolen_size; + u64 stolen_size, wopcm_size; u64 tile_offset; u64 tile_size; @@ -74,7 +97,13 @@ static s64 detect_bar2_dgfx(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr) if (drm_WARN_ON(&xe->drm, tile_size < mgr->stolen_base)) return 0; + /* Carve out the top of DSM as it contains the reserved WOPCM region */ + wopcm_size = get_wopcm_size(xe); + if (drm_WARN_ON(&xe->drm, !wopcm_size)) + return 0; + stolen_size = tile_size - mgr->stolen_base; + stolen_size -= wopcm_size; /* Verify usage fits in the actual resource available */ if (mgr->stolen_base + stolen_size <= pci_resource_len(pdev, LMEM_BAR)) @@ -89,29 +118,6 @@ static s64 detect_bar2_dgfx(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr) return ALIGN_DOWN(stolen_size, SZ_1M); } -static u32 get_wopcm_size(struct xe_device *xe) -{ - u32 wopcm_size; - u64 val; - - val = xe_mmio_read64_2x32(xe_root_tile_mmio(xe), STOLEN_RESERVED); - val = REG_FIELD_GET64(WOPCM_SIZE_MASK, val); - - switch (val) { - case 0x5 ... 0x6: - val--; - fallthrough; - case 0x0 ... 0x3: - wopcm_size = (1U << val) * SZ_1M; - break; - default: - WARN(1, "Missing case wopcm_size=%llx\n", val); - wopcm_size = 0; - } - - return wopcm_size; -} - static u32 detect_bar2_integrated(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr) { struct pci_dev *pdev = to_pci_dev(xe->drm.dev); From 768fec5ff7c1d1183edb14ff7d68b07edc98a6e1 Mon Sep 17 00:00:00 2001 From: Daniele Ceraolo Spurio Date: Tue, 4 Feb 2025 12:01:44 -0800 Subject: [PATCH 099/130] drm/xe/pxp: Don't use 0 to indicate NULL Explicitly using NULL is the correct approach. Reported-by: kernel test robot Closes: https://lore.kernel.org/oe-kbuild-all/202502050322.VUBMyUHc-lkp@intel.com/ Fixes: dcdd6b84d9ac ("drm/xe/pxp: Allocate PXP execution resources") Signed-off-by: Daniele Ceraolo Spurio Cc: John Harrison Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250204200144.1445800-1-daniele.ceraolospurio@intel.com --- drivers/gpu/drm/xe/xe_pxp_submit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_pxp_submit.c b/drivers/gpu/drm/xe/xe_pxp_submit.c index b50fe037c74b4..d92ec0f515b03 100644 --- a/drivers/gpu/drm/xe/xe_pxp_submit.c +++ b/drivers/gpu/drm/xe/xe_pxp_submit.c @@ -54,7 +54,7 @@ static int allocate_vcs_execution_resources(struct xe_pxp *pxp) * Each termination is 16 DWORDS, so 4K is enough to contain a * termination for each sessions. */ - bo = xe_bo_create_pin_map(xe, tile, 0, SZ_4K, ttm_bo_type_kernel, + bo = xe_bo_create_pin_map(xe, tile, NULL, SZ_4K, ttm_bo_type_kernel, XE_BO_FLAG_SYSTEM | XE_BO_FLAG_PINNED | XE_BO_FLAG_GGTT); if (IS_ERR(bo)) { err = PTR_ERR(bo); From 1d3ae92191fdff18f765936107d723401204cc12 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Fri, 31 Jan 2025 09:17:16 -0800 Subject: [PATCH 100/130] drm/xe/debugfs: Add node to dump guc log to dmesg Currently xe_guc_log_print_dmesg() is unused, as it's expected developers to add those calls when needed. However it makes it hard to guarantee it's working as nothing is testing it. Add a node in debugfs so it can be tested. This is purely for testing purposes since with the device probed and working, the guc log can be obtained by the regular debugfs file. Reviewed-by: Alan Previn Link: https://patchwork.freedesktop.org/patch/msgid/20250131171716.3998432-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_guc_debugfs.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_guc_debugfs.c b/drivers/gpu/drm/xe/xe_guc_debugfs.c index 0aff1d462bc01..c569ff456e741 100644 --- a/drivers/gpu/drm/xe/xe_guc_debugfs.c +++ b/drivers/gpu/drm/xe/xe_guc_debugfs.c @@ -48,6 +48,18 @@ static int guc_log(struct seq_file *m, void *data) return 0; } +static int guc_log_dmesg(struct seq_file *m, void *data) +{ + struct xe_guc *guc = node_to_guc(m->private); + struct xe_device *xe = guc_to_xe(guc); + + xe_pm_runtime_get(xe); + xe_guc_log_print_dmesg(&guc->log); + xe_pm_runtime_put(xe); + + return 0; +} + static int guc_ctb(struct seq_file *m, void *data) { struct xe_guc *guc = node_to_guc(m->private); @@ -77,6 +89,7 @@ static int guc_pc(struct seq_file *m, void *data) static const struct drm_info_list debugfs_list[] = { {"guc_info", guc_info, 0}, {"guc_log", guc_log, 0}, + {"guc_log_dmesg", guc_log_dmesg, 0}, {"guc_ctb", guc_ctb, 0}, {"guc_pc", guc_pc, 0}, }; From b7446752e5d3de98bf26b5d3a7ca4fe9165ec779 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Fri, 31 Jan 2025 06:50:14 -0500 Subject: [PATCH 101/130] drm/xe/display: Add missing watermark ipc update at runtime resume Continuing the alignment with i915 runtime pm sequence. Add this missing call. Reviewed-by: Jonathan Cavitt Link: https://patchwork.freedesktop.org/patch/msgid/20250131115014.29625-1-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/display/xe_display.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index 7f0d8f00acff7..376c36ca06db3 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -29,6 +29,7 @@ #include "intel_hdcp.h" #include "intel_hotplug.h" #include "intel_opregion.h" +#include "skl_watermark.h" #include "xe_module.h" /* Xe device functions */ @@ -481,6 +482,7 @@ void xe_display_pm_runtime_resume(struct xe_device *xe) intel_hpd_init(xe); intel_hpd_poll_disable(xe); + skl_watermark_ipc_update(xe); } From 1ed591582b7b894d2f7e7ab5cef2e9b0b6fef12b Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Wed, 12 Feb 2025 14:24:47 -0500 Subject: [PATCH 102/130] drm/xe/display: Remove hpd cancel work sync from runtime pm path This function will synchronously cancel and wait for many display work queue items, which might try to take the runtime pm reference causing a bad deadlock. So, remove it from the runtime_pm suspend patch. Reported-by: Imre Deak Reviewed-by: Imre Deak Link: https://patchwork.freedesktop.org/patch/msgid/20250212192447.402715-1-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/display/xe_display.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index 376c36ca06db3..e144d8c0a123f 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -312,7 +312,8 @@ static void __xe_display_pm_suspend(struct xe_device *xe, bool runtime) xe_display_flush_cleanup_work(xe); - intel_hpd_cancel_work(xe); + if (!runtime) + intel_hpd_cancel_work(xe); if (!runtime && has_display(xe)) { intel_display_driver_suspend_access(display); From b31e668d3111b100d16fd7db8db335328ce8c6d5 Mon Sep 17 00:00:00 2001 From: Shuicheng Lin Date: Thu, 13 Feb 2025 23:03:22 +0000 Subject: [PATCH 103/130] drm/xe/debugfs: Add missing xe_pm_runtime_put in wedge_mode_set xe_pm_runtime_put is missed in the failure path. Cc: Rodrigo Vivi Signed-off-by: Shuicheng Lin Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250213230322.1180621-1-shuicheng.lin@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_debugfs.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 56cb3788e7523..761e00cb64371 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -176,6 +176,7 @@ static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf, 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"); + xe_pm_runtime_put(xe); return -EIO; } } From 6884d2051011f4db9e2f0b85709c79a8ced13bd6 Mon Sep 17 00:00:00 2001 From: Xin Wang Date: Fri, 14 Feb 2025 06:36:15 +0800 Subject: [PATCH 104/130] drm/xe/debugfs: fixed the return value of wedged_mode_set It is generally expected that the write() function should return a positive value indicating the number of bytes written or a negative error code if an error occurs. Returning 0 is unusual and can lead to unexpected behavior. When the user program writes the same value to wedged_mode twice in a row, a lockup will occur, because the value expected to be returned by the write() function inside the program should be equal to the actual written value instead of 0. To reproduce the issue: echo 1 > /sys/kernel/debug/dri/0/wedged_mode echo 1 > /sys/kernel/debug/dri/0/wedged_mode <- lockup here Signed-off-by: Xin Wang Cc: Rodrigo Vivi Cc: Fei Yang Cc: Shuicheng Lin Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250213223615.2327367-1-x.wang@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/xe_debugfs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_debugfs.c b/drivers/gpu/drm/xe/xe_debugfs.c index 761e00cb64371..d0503959a8ed0 100644 --- a/drivers/gpu/drm/xe/xe_debugfs.c +++ b/drivers/gpu/drm/xe/xe_debugfs.c @@ -167,7 +167,7 @@ static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf, return -EINVAL; if (xe->wedged.mode == wedged_mode) - return 0; + return size; xe->wedged.mode = wedged_mode; From 776e3b502b6e49b1a72507d1a01a9b49d67fd843 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:28:57 -0800 Subject: [PATCH 105/130] drm/xe: Add callback support for driver remove MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit xe device probe uses devm cleanup in most places. However there are a few cases where this is not possible: when the driver interacts with component add/del. In that case, the resource group would be cleanup while the entire device resources are in the process of cleanup. One example is the xe_gsc_proxy and display using that to interact with mei and audio. Add a callback-based remove so the exception doesn't make the probe use multiple error handling styles. v2: Change internal API to mimic the devm API. This will make it easier to migrate in future when devm can be used. Cc: Daniele Ceraolo Spurio Cc: Rodrigo Vivi Cc: Thomas Hellström Reviewed-by: Rodrigo Vivi Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-1-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 68 ++++++++++++++++++++++++++++ drivers/gpu/drm/xe/xe_device.h | 3 ++ drivers/gpu/drm/xe/xe_device_types.h | 14 ++++++ drivers/gpu/drm/xe/xe_pci.c | 4 +- 4 files changed, 88 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index c641c802d4fb6..961df7d5ba636 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -65,6 +65,12 @@ #include +struct xe_device_remove_action { + struct list_head node; + void (*action)(void *); + void *data; +}; + static int xe_file_open(struct drm_device *dev, struct drm_file *file) { struct xe_device *xe = to_xe_device(dev); @@ -746,6 +752,9 @@ int xe_device_probe(struct xe_device *xe) u8 last_gt; u8 id; + xe->probing = true; + INIT_LIST_HEAD(&xe->remove_action_list); + xe_pat_init_early(xe); err = xe_sriov_init(xe); @@ -886,6 +895,8 @@ int xe_device_probe(struct xe_device *xe) xe_vsec_init(xe); + xe->probing = false; + return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe); err_fini_display: @@ -907,6 +918,61 @@ int xe_device_probe(struct xe_device *xe) return err; } +/** + * xe_device_call_remove_actions - Call the remove actions + * @xe: xe device instance + * + * This is only to be used by xe_pci and xe_device to call the remove actions + * while removing the driver or handling probe failures. + */ +void xe_device_call_remove_actions(struct xe_device *xe) +{ + struct xe_device_remove_action *ra, *tmp; + + list_for_each_entry_safe(ra, tmp, &xe->remove_action_list, node) { + ra->action(ra->data); + list_del(&ra->node); + kfree(ra); + } + + xe->probing = false; +} + +/** + * xe_device_add_action_or_reset - Add an action to run on driver removal + * @xe: xe device instance + * @action: Function that should be called on device remove + * @data: Pointer to data passed to @action implementation + * + * This adds a custom action to the list of remove callbacks executed on device + * remove, before any dev or drm managed resources are removed. This is only + * needed if the action leads to component_del()/component_master_del() since + * that is not compatible with devres cleanup. + * + * Returns: 0 on success or a negative error code on failure, in which case + * @action is already called. + */ +int xe_device_add_action_or_reset(struct xe_device *xe, + void (*action)(void *), void *data) +{ + struct xe_device_remove_action *ra; + + drm_WARN_ON(&xe->drm, !xe->probing); + + ra = kmalloc(sizeof(*ra), GFP_KERNEL); + if (!ra) { + action(data); + return -ENOMEM; + } + + INIT_LIST_HEAD(&ra->node); + ra->action = action; + ra->data = data; + list_add(&ra->node, &xe->remove_action_list); + + return 0; +} + static void xe_device_remove_display(struct xe_device *xe) { xe_display_unregister(xe); @@ -932,6 +998,8 @@ void xe_device_remove(struct xe_device *xe) for_each_gt(gt, xe, id) xe_gt_remove(gt); + + xe_device_call_remove_actions(xe); } void xe_device_shutdown(struct xe_device *xe) diff --git a/drivers/gpu/drm/xe/xe_device.h b/drivers/gpu/drm/xe/xe_device.h index 0bc3bc8e68030..079dad32a6f53 100644 --- a/drivers/gpu/drm/xe/xe_device.h +++ b/drivers/gpu/drm/xe/xe_device.h @@ -45,6 +45,9 @@ struct xe_device *xe_device_create(struct pci_dev *pdev, const struct pci_device_id *ent); int xe_device_probe_early(struct xe_device *xe); int xe_device_probe(struct xe_device *xe); +int xe_device_add_action_or_reset(struct xe_device *xe, + void (*action)(void *), void *data); +void xe_device_call_remove_actions(struct xe_device *xe); void xe_device_remove(struct xe_device *xe); void xe_device_shutdown(struct xe_device *xe); diff --git a/drivers/gpu/drm/xe/xe_device_types.h b/drivers/gpu/drm/xe/xe_device_types.h index 28d10a1d7b649..4cf08c408b957 100644 --- a/drivers/gpu/drm/xe/xe_device_types.h +++ b/drivers/gpu/drm/xe/xe_device_types.h @@ -428,6 +428,20 @@ struct xe_device { /** @tiles: device tiles */ struct xe_tile tiles[XE_MAX_TILES_PER_DEVICE]; + /** + * @remove_action_list: list of actions to execute on device remove. + * Use xe_device_add_remove_action() for that. Actions can only be added + * during probe and are executed during the call from PCI subsystem to + * remove the driver from the device. + */ + struct list_head remove_action_list; + + /** + * @probing: cover the section in which @remove_action_list can be used + * to post cleaning actions + */ + bool probing; + /** * @mem_access: keep track of memory access in the device, possibly * triggering additional actions when they occur. diff --git a/drivers/gpu/drm/xe/xe_pci.c b/drivers/gpu/drm/xe/xe_pci.c index 663bfc29cddc1..f8417f4d8ce6d 100644 --- a/drivers/gpu/drm/xe/xe_pci.c +++ b/drivers/gpu/drm/xe/xe_pci.c @@ -900,8 +900,10 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) return err; err = xe_device_probe(xe); - if (err) + if (err) { + xe_device_call_remove_actions(xe); return err; + } err = xe_pm_init(xe); if (err) From 8b3f09fb44a3b4e88c87a4654f4bf859c2c6447e Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:28:58 -0800 Subject: [PATCH 106/130] drm/xe: Fix xe_display_fini() calls xe_display_fini() undoes things from xe_display_init() (technically from intel_display_driver_probe()). Those `goto err` in xe_device_probe() were wrong and being accumulated over time. Commit 65e366ace5ee ("drm/xe/display: Use a single early init call for display") made it easier to fix now that we don't have xe_display_* init calls spread on xe_device_probe(). Change xe_display_init() to use devm_add_action_or_reset() that will finalize display in the right order. While at it, also add a newline and comment about calling xe_driver_flr_fini. Cc: Maarten Lankhorst Cc: Rodrigo Vivi Reviewed-by: Rodrigo Vivi Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-2-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/display/xe_display.c | 22 ++++++++++++---------- drivers/gpu/drm/xe/display/xe_display.h | 2 -- drivers/gpu/drm/xe/xe_device.c | 21 +++++++++++---------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index e144d8c0a123f..ac0804726e550 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -162,27 +162,29 @@ int xe_display_init_early(struct xe_device *xe) return err; } -int xe_display_init(struct xe_device *xe) +static void xe_display_fini(void *arg) { + struct xe_device *xe = arg; struct intel_display *display = &xe->display; - if (!xe->info.probe_display) - return 0; - - return intel_display_driver_probe(display); + intel_hpd_poll_fini(xe); + intel_hdcp_component_fini(display); + intel_audio_deinit(xe); } -void xe_display_fini(struct xe_device *xe) +int xe_display_init(struct xe_device *xe) { struct intel_display *display = &xe->display; + int err; if (!xe->info.probe_display) - return; + return 0; - intel_hpd_poll_fini(xe); + err = intel_display_driver_probe(display); + if (err) + return err; - intel_hdcp_component_fini(display); - intel_audio_deinit(xe); + return xe_device_add_action_or_reset(xe, xe_display_fini, xe); } void xe_display_register(struct xe_device *xe) diff --git a/drivers/gpu/drm/xe/display/xe_display.h b/drivers/gpu/drm/xe/display/xe_display.h index e2a99624f7064..685dc74402fb8 100644 --- a/drivers/gpu/drm/xe/display/xe_display.h +++ b/drivers/gpu/drm/xe/display/xe_display.h @@ -22,7 +22,6 @@ int xe_display_probe(struct xe_device *xe); int xe_display_init_early(struct xe_device *xe); int xe_display_init(struct xe_device *xe); -void xe_display_fini(struct xe_device *xe); void xe_display_register(struct xe_device *xe); void xe_display_unregister(struct xe_device *xe); @@ -54,7 +53,6 @@ static inline int xe_display_probe(struct xe_device *xe) { return 0; } static inline int xe_display_init_early(struct xe_device *xe) { return 0; } static inline int xe_display_init(struct xe_device *xe) { return 0; } -static inline void xe_display_fini(struct xe_device *xe) {} static inline void xe_display_register(struct xe_device *xe) {} static inline void xe_display_unregister(struct xe_device *xe) {} diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 961df7d5ba636..1084beef27e31 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -741,6 +741,7 @@ static int probe_has_flat_ccs(struct xe_device *xe) "Flat CCS has been disabled in bios, May lead to performance impact"); xe_force_wake_put(gt_to_fw(gt), fw_ref); + return 0; } @@ -812,22 +813,26 @@ int xe_device_probe(struct xe_device *xe) err = xe_devcoredump_init(xe); if (err) return err; + + /* + * From here on, if a step fails, make sure a Driver-FLR is triggereed + */ err = devm_add_action_or_reset(xe->drm.dev, xe_driver_flr_fini, xe); if (err) return err; err = probe_has_flat_ccs(xe); if (err) - goto err; + return err; err = xe_vram_probe(xe); if (err) - goto err; + return err; for_each_tile(tile, xe, id) { err = xe_tile_init_noalloc(tile); if (err) - goto err; + return err; } /* Allocate and map stolen after potential VRAM resize */ @@ -841,17 +846,17 @@ int xe_device_probe(struct xe_device *xe) */ err = xe_display_init_early(xe); if (err) - goto err; + return err; for_each_tile(tile, xe, id) { err = xe_tile_init(tile); if (err) - goto err; + return err; } err = xe_irq_install(xe); if (err) - goto err; + return err; for_each_gt(gt, xe, id) { last_gt = id; @@ -913,8 +918,6 @@ int xe_device_probe(struct xe_device *xe) break; } -err: - xe_display_fini(xe); return err; } @@ -990,8 +993,6 @@ void xe_device_remove(struct xe_device *xe) xe_device_remove_display(xe); - xe_display_fini(xe); - xe_oa_fini(xe); xe_heci_gsc_fini(xe); From 121b214cdf10d4129b64f2b1f31807154c74ae55 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:28:59 -0800 Subject: [PATCH 107/130] drm/xe: Fix error handling in xe_irq_install() When devm_add_action_or_reset() fails, it already calls the function passed as parameter and that function is already free'ing the irqs. Drop the goto and just return. The caller, xe_device_probe(), should also do the same thing instead of wrongly doing `goto err` and calling the unrelated xe_display_fini() function. Fixes: 14d25d8d684d ("drm/xe: change old msi irq api to a new one") Reviewed-by: Rodrigo Vivi Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-3-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_irq.c | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_irq.c b/drivers/gpu/drm/xe/xe_irq.c index bf092e6391c7d..5362d3174b060 100644 --- a/drivers/gpu/drm/xe/xe_irq.c +++ b/drivers/gpu/drm/xe/xe_irq.c @@ -775,19 +775,7 @@ int xe_irq_install(struct xe_device *xe) xe_irq_postinstall(xe); - err = devm_add_action_or_reset(xe->drm.dev, irq_uninstall, xe); - if (err) - goto free_irq_handler; - - return 0; - -free_irq_handler: - if (xe_device_has_msix(xe)) - xe_irq_msix_free(xe); - else - xe_irq_msi_free(xe); - - return err; + return devm_add_action_or_reset(xe->drm.dev, irq_uninstall, xe); } static void xe_irq_msi_synchronize_irq(struct xe_device *xe) From 0bcf41171c64234e79eb3552d00f0aad8a47e8d3 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:00 -0800 Subject: [PATCH 108/130] drm/xe: Fix xe_tile_init_noalloc() error propagation Propagate the error to the caller so initialization properly stops if sysfs creation fails. Reviewed-by: Francois Dugast Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-4-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_tile.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_tile.c b/drivers/gpu/drm/xe/xe_tile.c index d9a7a04ff652f..d29658ff4dd41 100644 --- a/drivers/gpu/drm/xe/xe_tile.c +++ b/drivers/gpu/drm/xe/xe_tile.c @@ -168,9 +168,7 @@ int xe_tile_init_noalloc(struct xe_tile *tile) xe_wa_apply_tile_workarounds(tile); - err = xe_tile_sysfs_init(tile); - - return 0; + return xe_tile_sysfs_init(tile); } int xe_tile_init(struct xe_tile *tile) From ff57025c358603555f1e0ae0d50282a460433594 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:01 -0800 Subject: [PATCH 109/130] drm/xe: Stop ignoring errors from xe_ttm_stolen_mgr_init() Make sure to differentiate normal behavior, e.g. there's no stolen, from allocation errors or failure to initialize lower layers. Reviewed-by: Francois Dugast Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-5-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 4 +++- drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c | 17 +++++++++-------- drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 1084beef27e31..2e934ed02713d 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -836,7 +836,9 @@ int xe_device_probe(struct xe_device *xe) } /* Allocate and map stolen after potential VRAM resize */ - xe_ttm_stolen_mgr_init(xe); + err = xe_ttm_stolen_mgr_init(xe); + if (err) + return err; /* * Now that GT is initialized (TTM in particular), diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c index d414421f8c131..d9c9d2547aadf 100644 --- a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c +++ b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.c @@ -207,17 +207,16 @@ static u64 detect_stolen(struct xe_device *xe, struct xe_ttm_stolen_mgr *mgr) #endif } -void xe_ttm_stolen_mgr_init(struct xe_device *xe) +int xe_ttm_stolen_mgr_init(struct xe_device *xe) { - struct xe_ttm_stolen_mgr *mgr = drmm_kzalloc(&xe->drm, sizeof(*mgr), GFP_KERNEL); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); + struct xe_ttm_stolen_mgr *mgr; u64 stolen_size, io_size; int err; - if (!mgr) { - drm_dbg_kms(&xe->drm, "Stolen mgr init failed\n"); - return; - } + mgr = drmm_kzalloc(&xe->drm, sizeof(*mgr), GFP_KERNEL); + if (!mgr) + return -ENOMEM; if (IS_SRIOV_VF(xe)) stolen_size = 0; @@ -230,7 +229,7 @@ void xe_ttm_stolen_mgr_init(struct xe_device *xe) if (!stolen_size) { drm_dbg_kms(&xe->drm, "No stolen memory support\n"); - return; + return 0; } /* @@ -246,7 +245,7 @@ void xe_ttm_stolen_mgr_init(struct xe_device *xe) io_size, PAGE_SIZE); if (err) { drm_dbg_kms(&xe->drm, "Stolen mgr init failed: %i\n", err); - return; + return err; } drm_dbg_kms(&xe->drm, "Initialized stolen memory support with %llu bytes\n", @@ -254,6 +253,8 @@ void xe_ttm_stolen_mgr_init(struct xe_device *xe) if (io_size) mgr->mapping = devm_ioremap_wc(&pdev->dev, mgr->io_base, io_size); + + return 0; } u64 xe_ttm_stolen_io_offset(struct xe_bo *bo, u32 offset) diff --git a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h index 1777245ff8101..8e877d1e839bd 100644 --- a/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h +++ b/drivers/gpu/drm/xe/xe_ttm_stolen_mgr.h @@ -12,7 +12,7 @@ struct ttm_resource; struct xe_bo; struct xe_device; -void xe_ttm_stolen_mgr_init(struct xe_device *xe); +int xe_ttm_stolen_mgr_init(struct xe_device *xe); int xe_ttm_stolen_io_mem_reserve(struct xe_device *xe, struct ttm_resource *mem); bool xe_ttm_stolen_cpu_access_needs_ggtt(struct xe_device *xe); u64 xe_ttm_stolen_io_offset(struct xe_bo *bo, u32 offset); From c0aeb90b28b88fa2eedef4eae4bd649de6fc2a3e Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:02 -0800 Subject: [PATCH 110/130] drm/xe: Remove leftover pxp comment Not being able to initialize pxp is fatal if the platform is expected to have it. Update comment after commit 9c9dc9ba4a00 ("drm/xe/pxp: Fail the load if PXP fails to initialize"). Cc: Daniele Ceraolo Spurio Reviewed-by: Daniele Ceraolo Spurio Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-6-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 2e934ed02713d..8203c80faca5d 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -878,7 +878,6 @@ int xe_device_probe(struct xe_device *xe) if (err) goto err_fini_oa; - /* A PXP init failure is not fatal */ err = xe_pxp_init(xe); if (err) goto err_fini_display; From ff6cd29b690b11fff7d1d998852fc6eeb02bed73 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:03 -0800 Subject: [PATCH 111/130] drm/xe: Cleanup unwind of gt initialization MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The only thing in xe_gt_remove() that really needs to happen on the device remove callback is the xe_uc_remove(). That's because of the following call chain: xe_gt_remove() xe_uc_remove() xe_gsc_remove() xe_gsc_proxy_remove() Move xe_gsc_proxy_remove() to be handled as a xe_device_remove_action, so it's recorded when it should run during device removal. The rest can be handled normally by devm infra. Besides removing the deep call chain above, xe_device_probe() doesn't have to unwind the gt loop and it's also more in line with the xe_device_probe() style. Cc: Daniele Ceraolo Spurio Cc: Rodrigo Vivi Cc: Thomas Hellström Reviewed-by: Daniele Ceraolo Spurio Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-7-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 21 +---------- drivers/gpu/drm/xe/xe_gsc.c | 9 ----- drivers/gpu/drm/xe/xe_gsc.h | 1 - drivers/gpu/drm/xe/xe_gsc_proxy.c | 63 ++++++++++++++----------------- drivers/gpu/drm/xe/xe_gsc_proxy.h | 1 - drivers/gpu/drm/xe/xe_gsc_types.h | 1 + drivers/gpu/drm/xe/xe_gt.c | 35 ++++++++--------- drivers/gpu/drm/xe/xe_gt.h | 1 - drivers/gpu/drm/xe/xe_uc.c | 13 ------- drivers/gpu/drm/xe/xe_uc.h | 1 - 10 files changed, 47 insertions(+), 99 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 8203c80faca5d..398fad6c53658 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -750,7 +750,6 @@ int xe_device_probe(struct xe_device *xe) struct xe_tile *tile; struct xe_gt *gt; int err; - u8 last_gt; u8 id; xe->probing = true; @@ -861,18 +860,16 @@ int xe_device_probe(struct xe_device *xe) return err; for_each_gt(gt, xe, id) { - last_gt = id; - err = xe_gt_init(gt); if (err) - goto err_fini_gt; + return err; } xe_heci_gsc_init(xe); err = xe_oa_init(xe); if (err) - goto err_fini_gt; + return err; err = xe_display_init(xe); if (err) @@ -911,14 +908,6 @@ int xe_device_probe(struct xe_device *xe) err_fini_oa: xe_oa_fini(xe); -err_fini_gt: - for_each_gt(gt, xe, id) { - if (id < last_gt) - xe_gt_remove(gt); - else - break; - } - return err; } @@ -987,9 +976,6 @@ static void xe_device_remove_display(struct xe_device *xe) void xe_device_remove(struct xe_device *xe) { - struct xe_gt *gt; - u8 id; - xe_oa_unregister(xe); xe_device_remove_display(xe); @@ -998,9 +984,6 @@ void xe_device_remove(struct xe_device *xe) xe_heci_gsc_fini(xe); - for_each_gt(gt, xe, id) - xe_gt_remove(gt); - xe_device_call_remove_actions(xe); } diff --git a/drivers/gpu/drm/xe/xe_gsc.c b/drivers/gpu/drm/xe/xe_gsc.c index 1eb791ddc375c..fd41113f85725 100644 --- a/drivers/gpu/drm/xe/xe_gsc.c +++ b/drivers/gpu/drm/xe/xe_gsc.c @@ -555,15 +555,6 @@ void xe_gsc_wait_for_worker_completion(struct xe_gsc *gsc) flush_work(&gsc->work); } -/** - * xe_gsc_remove() - Clean up the GSC structures before driver removal - * @gsc: the GSC uC - */ -void xe_gsc_remove(struct xe_gsc *gsc) -{ - xe_gsc_proxy_remove(gsc); -} - /* * wa_14015076503: if the GSC FW is loaded, we need to alert it before doing a * GSC engine reset by writing a notification bit in the GS1 register and then diff --git a/drivers/gpu/drm/xe/xe_gsc.h b/drivers/gpu/drm/xe/xe_gsc.h index e282b9ef6ec4d..d99f66c38075c 100644 --- a/drivers/gpu/drm/xe/xe_gsc.h +++ b/drivers/gpu/drm/xe/xe_gsc.h @@ -17,7 +17,6 @@ int xe_gsc_init(struct xe_gsc *gsc); int xe_gsc_init_post_hwconfig(struct xe_gsc *gsc); void xe_gsc_wait_for_worker_completion(struct xe_gsc *gsc); void xe_gsc_load_start(struct xe_gsc *gsc); -void xe_gsc_remove(struct xe_gsc *gsc); void xe_gsc_hwe_irq_handler(struct xe_hw_engine *hwe, u16 intr_vec); void xe_gsc_wa_14015076503(struct xe_gt *gt, bool prep); diff --git a/drivers/gpu/drm/xe/xe_gsc_proxy.c b/drivers/gpu/drm/xe/xe_gsc_proxy.c index 24cc6a4f9a96a..31c90577faf0b 100644 --- a/drivers/gpu/drm/xe/xe_gsc_proxy.c +++ b/drivers/gpu/drm/xe/xe_gsc_proxy.c @@ -423,6 +423,34 @@ static int proxy_channel_alloc(struct xe_gsc *gsc) return 0; } +static void xe_gsc_proxy_remove(void *arg) +{ + struct xe_gsc *gsc = arg; + struct xe_gt *gt = gsc_to_gt(gsc); + struct xe_device *xe = gt_to_xe(gt); + unsigned int fw_ref = 0; + + if (!gsc->proxy.component_added) + return; + + /* disable HECI2 IRQs */ + xe_pm_runtime_get(xe); + fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC); + if (!fw_ref) + xe_gt_err(gt, "failed to get forcewake to disable GSC interrupts\n"); + + /* try do disable irq even if forcewake failed */ + gsc_proxy_irq_toggle(gsc, false); + + xe_force_wake_put(gt_to_fw(gt), fw_ref); + xe_pm_runtime_put(xe); + + xe_gsc_wait_for_worker_completion(gsc); + + component_del(xe->drm.dev, &xe_gsc_proxy_component_ops); + gsc->proxy.component_added = false; +} + /** * xe_gsc_proxy_init() - init objects and MEI component required by GSC proxy * @gsc: the GSC uC @@ -462,40 +490,7 @@ int xe_gsc_proxy_init(struct xe_gsc *gsc) gsc->proxy.component_added = true; - /* the component must be removed before unload, so can't use drmm for cleanup */ - - return 0; -} - -/** - * xe_gsc_proxy_remove() - remove the GSC proxy MEI component - * @gsc: the GSC uC - */ -void xe_gsc_proxy_remove(struct xe_gsc *gsc) -{ - struct xe_gt *gt = gsc_to_gt(gsc); - struct xe_device *xe = gt_to_xe(gt); - unsigned int fw_ref = 0; - - if (!gsc->proxy.component_added) - return; - - /* disable HECI2 IRQs */ - xe_pm_runtime_get(xe); - fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC); - if (!fw_ref) - xe_gt_err(gt, "failed to get forcewake to disable GSC interrupts\n"); - - /* try do disable irq even if forcewake failed */ - gsc_proxy_irq_toggle(gsc, false); - - xe_force_wake_put(gt_to_fw(gt), fw_ref); - xe_pm_runtime_put(xe); - - xe_gsc_wait_for_worker_completion(gsc); - - component_del(xe->drm.dev, &xe_gsc_proxy_component_ops); - gsc->proxy.component_added = false; + return xe_device_add_action_or_reset(xe, xe_gsc_proxy_remove, gsc); } /** diff --git a/drivers/gpu/drm/xe/xe_gsc_proxy.h b/drivers/gpu/drm/xe/xe_gsc_proxy.h index c511ade6b8637..fdef56995cd43 100644 --- a/drivers/gpu/drm/xe/xe_gsc_proxy.h +++ b/drivers/gpu/drm/xe/xe_gsc_proxy.h @@ -12,7 +12,6 @@ struct xe_gsc; int xe_gsc_proxy_init(struct xe_gsc *gsc); bool xe_gsc_proxy_init_done(struct xe_gsc *gsc); -void xe_gsc_proxy_remove(struct xe_gsc *gsc); int xe_gsc_proxy_start(struct xe_gsc *gsc); int xe_gsc_proxy_request_handler(struct xe_gsc *gsc); diff --git a/drivers/gpu/drm/xe/xe_gsc_types.h b/drivers/gpu/drm/xe/xe_gsc_types.h index 5926de20214c8..97c056656df05 100644 --- a/drivers/gpu/drm/xe/xe_gsc_types.h +++ b/drivers/gpu/drm/xe/xe_gsc_types.h @@ -13,6 +13,7 @@ #include #include "xe_uc_fw_types.h" +#include "xe_device_types.h" struct xe_bo; struct xe_exec_queue; diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index 9fb8f1e678dc8..c33040278e1aa 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -141,26 +141,6 @@ static void xe_gt_disable_host_l2_vram(struct xe_gt *gt) xe_force_wake_put(gt_to_fw(gt), fw_ref); } -/** - * xe_gt_remove() - Clean up the GT structures before driver removal - * @gt: the GT object - * - * This function should only act on objects/structures that must be cleaned - * before the driver removal callback is complete and therefore can't be - * deferred to a drmm action. - */ -void xe_gt_remove(struct xe_gt *gt) -{ - int i; - - xe_uc_remove(>->uc); - - for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) - xe_hw_fence_irq_finish(>->fence_irq[i]); - - xe_gt_disable_host_l2_vram(gt); -} - static void gt_reset_worker(struct work_struct *w); static int emit_nop_job(struct xe_gt *gt, struct xe_exec_queue *q) @@ -583,6 +563,17 @@ int xe_gt_init_hwconfig(struct xe_gt *gt) return err; } +static void xe_gt_fini(void *arg) +{ + struct xe_gt *gt = arg; + int i; + + for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) + xe_hw_fence_irq_finish(>->fence_irq[i]); + + xe_gt_disable_host_l2_vram(gt); +} + int xe_gt_init(struct xe_gt *gt) { int err; @@ -595,6 +586,10 @@ int xe_gt_init(struct xe_gt *gt) xe_hw_fence_irq_init(>->fence_irq[i]); } + err = devm_add_action_or_reset(gt_to_xe(gt)->drm.dev, xe_gt_fini, gt); + if (err) + return err; + err = xe_gt_pagefault_init(gt); if (err) return err; diff --git a/drivers/gpu/drm/xe/xe_gt.h b/drivers/gpu/drm/xe/xe_gt.h index e504cc33ade4f..187fa6490eafc 100644 --- a/drivers/gpu/drm/xe/xe_gt.h +++ b/drivers/gpu/drm/xe/xe_gt.h @@ -54,7 +54,6 @@ int xe_gt_resume(struct xe_gt *gt); void xe_gt_reset_async(struct xe_gt *gt); void xe_gt_sanitize(struct xe_gt *gt); int xe_gt_sanitize_freq(struct xe_gt *gt); -void xe_gt_remove(struct xe_gt *gt); /** * xe_gt_wait_for_reset - wait for gt's async reset to finalize. diff --git a/drivers/gpu/drm/xe/xe_uc.c b/drivers/gpu/drm/xe/xe_uc.c index 0d073a9987c2e..d8167e818280b 100644 --- a/drivers/gpu/drm/xe/xe_uc.c +++ b/drivers/gpu/drm/xe/xe_uc.c @@ -288,19 +288,6 @@ int xe_uc_suspend(struct xe_uc *uc) return xe_guc_suspend(&uc->guc); } -/** - * xe_uc_remove() - Clean up the UC structures before driver removal - * @uc: the UC object - * - * This function should only act on objects/structures that must be cleaned - * before the driver removal callback is complete and therefore can't be - * deferred to a drmm action. - */ -void xe_uc_remove(struct xe_uc *uc) -{ - xe_gsc_remove(&uc->gsc); -} - /** * xe_uc_declare_wedged() - Declare UC wedged * @uc: the UC object diff --git a/drivers/gpu/drm/xe/xe_uc.h b/drivers/gpu/drm/xe/xe_uc.h index 506517c113339..3813c1ede450e 100644 --- a/drivers/gpu/drm/xe/xe_uc.h +++ b/drivers/gpu/drm/xe/xe_uc.h @@ -20,7 +20,6 @@ void xe_uc_stop(struct xe_uc *uc); int xe_uc_start(struct xe_uc *uc); int xe_uc_suspend(struct xe_uc *uc); int xe_uc_sanitize_reset(struct xe_uc *uc); -void xe_uc_remove(struct xe_uc *uc); void xe_uc_declare_wedged(struct xe_uc *uc); #endif From f5ebe80e32f809a52d4f562602f791c350c4a204 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:04 -0800 Subject: [PATCH 112/130] drm/xe: Cleanup extra calls to xe_hw_fence_irq_finish() Now that xe_gt_remove is handled entirely by xe_gt, it's clear there are some extra calls to xe_hw_fence_irq_finish() that aren't necessary. Neither all_fw_domain_init() or gt_fw_domain_init() need to do that since it's handled by the caller on any error. Reviewed-by: Rodrigo Vivi Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-8-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_gt.c | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index c33040278e1aa..bd16ca070dd20 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -389,13 +389,11 @@ static void dump_pat_on_error(struct xe_gt *gt) static int gt_fw_domain_init(struct xe_gt *gt) { unsigned int fw_ref; - int err, i; + int err; fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); - if (!fw_ref) { - err = -ETIMEDOUT; - goto err_hw_fence_irq; - } + if (!fw_ref) + return -ETIMEDOUT; if (!xe_gt_is_media_type(gt)) { err = xe_ggtt_init(gt_to_tile(gt)->mem.ggtt); @@ -436,9 +434,6 @@ static int gt_fw_domain_init(struct xe_gt *gt) err_force_wake: dump_pat_on_error(gt); xe_force_wake_put(gt_to_fw(gt), fw_ref); -err_hw_fence_irq: - for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) - xe_hw_fence_irq_finish(>->fence_irq[i]); return err; } @@ -446,7 +441,7 @@ static int gt_fw_domain_init(struct xe_gt *gt) static int all_fw_domain_init(struct xe_gt *gt) { unsigned int fw_ref; - int err, i; + int err; fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { @@ -524,8 +519,6 @@ static int all_fw_domain_init(struct xe_gt *gt) err_force_wake: xe_force_wake_put(gt_to_fw(gt), fw_ref); - for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) - xe_hw_fence_irq_finish(>->fence_irq[i]); return err; } From d3f557d52e2d1be48adf89a6c1e47cc8728b9054 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:05 -0800 Subject: [PATCH 113/130] drm/xe/oa: Move fini to xe_oa Like done with other functions, cleanup the error handling in xe_device_probe() by moving the OA fini to be handled by xe_oa itself, which relies on devm to call the cleanup function. Reviewed-by: Ashutosh Dixit Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-9-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 7 +---- drivers/gpu/drm/xe/xe_oa.c | 48 +++++++++++++++++----------------- drivers/gpu/drm/xe/xe_oa.h | 1 - 3 files changed, 25 insertions(+), 31 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 398fad6c53658..d0b1c280ddd3a 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -873,7 +873,7 @@ int xe_device_probe(struct xe_device *xe) err = xe_display_init(xe); if (err) - goto err_fini_oa; + return err; err = xe_pxp_init(xe); if (err) @@ -905,9 +905,6 @@ int xe_device_probe(struct xe_device *xe) err_fini_display: xe_display_driver_remove(xe); -err_fini_oa: - xe_oa_fini(xe); - return err; } @@ -980,8 +977,6 @@ void xe_device_remove(struct xe_device *xe) xe_device_remove_display(xe); - xe_oa_fini(xe); - xe_heci_gsc_fini(xe); xe_device_call_remove_actions(xe); diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index fa873f3d0a9d1..2c640185bdeca 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -2641,6 +2641,27 @@ static void xe_oa_init_supported_formats(struct xe_oa *oa) } } +static int destroy_config(int id, void *p, void *data) +{ + xe_oa_config_put(p); + + return 0; +} + +static void xe_oa_fini(void *arg) +{ + struct xe_device *xe = arg; + struct xe_oa *oa = &xe->oa; + + if (!oa->xe) + return; + + idr_for_each(&oa->metrics_idr, destroy_config, oa); + idr_destroy(&oa->metrics_idr); + + oa->xe = NULL; +} + /** * xe_oa_init - OA initialization during device probe * @xe: @xe_device @@ -2672,31 +2693,10 @@ int xe_oa_init(struct xe_device *xe) } xe_oa_init_supported_formats(oa); - return 0; -exit: - oa->xe = NULL; - return ret; -} -static int destroy_config(int id, void *p, void *data) -{ - xe_oa_config_put(p); - return 0; -} - -/** - * xe_oa_fini - OA de-initialization during device remove - * @xe: @xe_device - */ -void xe_oa_fini(struct xe_device *xe) -{ - struct xe_oa *oa = &xe->oa; - - if (!oa->xe) - return; - - idr_for_each(&oa->metrics_idr, destroy_config, oa); - idr_destroy(&oa->metrics_idr); + return devm_add_action_or_reset(xe->drm.dev, xe_oa_fini, xe); +exit: oa->xe = NULL; + return ret; } diff --git a/drivers/gpu/drm/xe/xe_oa.h b/drivers/gpu/drm/xe/xe_oa.h index 87a38820c317d..eb36ce250c615 100644 --- a/drivers/gpu/drm/xe/xe_oa.h +++ b/drivers/gpu/drm/xe/xe_oa.h @@ -15,7 +15,6 @@ struct xe_gt; struct xe_hw_engine; int xe_oa_init(struct xe_device *xe); -void xe_oa_fini(struct xe_device *xe); void xe_oa_register(struct xe_device *xe); void xe_oa_unregister(struct xe_device *xe); int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *file); From 00f6a86c3c5ec14fc0b51cd7b4662817067c652b Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:06 -0800 Subject: [PATCH 114/130] drm/xe: Move drm_dev_unplug() out of display function This is not really display-related and needed for any sequence on driver removal that has to interact with drm_dev_enter()/drm_dev_exit(). Just remove xe_device_remove_display() and inline it in the single caller to make clear this is not done only for display. Cc: Rodrigo Vivi Cc: Jani Nikula Reviewed-by: Tejas Upadhyay Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-10-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index d0b1c280ddd3a..6d01932f934c5 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -963,20 +963,16 @@ int xe_device_add_action_or_reset(struct xe_device *xe, return 0; } -static void xe_device_remove_display(struct xe_device *xe) +void xe_device_remove(struct xe_device *xe) { xe_display_unregister(xe); drm_dev_unplug(&xe->drm); + xe_display_driver_remove(xe); -} -void xe_device_remove(struct xe_device *xe) -{ xe_oa_unregister(xe); - xe_device_remove_display(xe); - xe_heci_gsc_fini(xe); xe_device_call_remove_actions(xe); From 960d71044eee8d7ca407ea272989de34f0e718f3 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:07 -0800 Subject: [PATCH 115/130] drm/xe/oa: Handle errors in xe_oa_register() Let xe_oa_unregister() be handled by devm infra since it's only putting the kobject. Also, since kobject_create_and_add may fail, handle the error accordingly. Reviewed-by: Ashutosh Dixit Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-11-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 14 ++++++++------ drivers/gpu/drm/xe/xe_oa.c | 30 +++++++++++++++--------------- drivers/gpu/drm/xe/xe_oa.h | 3 +-- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 6d01932f934c5..89a85f193f3af 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -877,15 +877,17 @@ int xe_device_probe(struct xe_device *xe) err = xe_pxp_init(xe); if (err) - goto err_fini_display; + goto err_remove_display; err = drm_dev_register(&xe->drm, 0); if (err) - goto err_fini_display; + goto err_remove_display; xe_display_register(xe); - xe_oa_register(xe); + err = xe_oa_register(xe); + if (err) + goto err_unregister_display; xe_pmu_register(&xe->pmu); @@ -902,7 +904,9 @@ int xe_device_probe(struct xe_device *xe) return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe); -err_fini_display: +err_unregister_display: + xe_display_unregister(xe); +err_remove_display: xe_display_driver_remove(xe); return err; @@ -971,8 +975,6 @@ void xe_device_remove(struct xe_device *xe) xe_display_driver_remove(xe); - xe_oa_unregister(xe); - xe_heci_gsc_fini(xe); xe_device_call_remove_actions(xe); diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index 2c640185bdeca..d89e6cabf5a56 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -2423,36 +2423,36 @@ int xe_oa_remove_config_ioctl(struct drm_device *dev, u64 data, struct drm_file return ret; } +static void xe_oa_unregister(void *arg) +{ + struct xe_oa *oa = arg; + + if (!oa->metrics_kobj) + return; + + kobject_put(oa->metrics_kobj); + oa->metrics_kobj = NULL; +} + /** * xe_oa_register - Xe OA registration * @xe: @xe_device * * Exposes the metrics sysfs directory upon completion of module initialization */ -void xe_oa_register(struct xe_device *xe) +int xe_oa_register(struct xe_device *xe) { struct xe_oa *oa = &xe->oa; if (!oa->xe) - return; + return 0; oa->metrics_kobj = kobject_create_and_add("metrics", &xe->drm.primary->kdev->kobj); -} - -/** - * xe_oa_unregister - Xe OA de-registration - * @xe: @xe_device - */ -void xe_oa_unregister(struct xe_device *xe) -{ - struct xe_oa *oa = &xe->oa; - if (!oa->metrics_kobj) - return; + return -ENOMEM; - kobject_put(oa->metrics_kobj); - oa->metrics_kobj = NULL; + return devm_add_action_or_reset(xe->drm.dev, xe_oa_unregister, oa); } static u32 num_oa_units_per_gt(struct xe_gt *gt) diff --git a/drivers/gpu/drm/xe/xe_oa.h b/drivers/gpu/drm/xe/xe_oa.h index eb36ce250c615..e510826f9efc6 100644 --- a/drivers/gpu/drm/xe/xe_oa.h +++ b/drivers/gpu/drm/xe/xe_oa.h @@ -15,8 +15,7 @@ struct xe_gt; struct xe_hw_engine; int xe_oa_init(struct xe_device *xe); -void xe_oa_register(struct xe_device *xe); -void xe_oa_unregister(struct xe_device *xe); +int xe_oa_register(struct xe_device *xe); int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *file); int xe_oa_add_config_ioctl(struct drm_device *dev, u64 data, struct drm_file *file); int xe_oa_remove_config_ioctl(struct drm_device *dev, u64 data, struct drm_file *file); From 6b5506158f902b3d427f76b0c243d025de40b333 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:08 -0800 Subject: [PATCH 116/130] drm/xe/pmu: Fail probe if xe_pmu_register() fails Now that previous callers in xe_device_probe() are handling the errors, that can be done for xe_pmu_register() as well. Cc: Riana Tauro Cc: Vinay Belgaumkar Reviewed-by: Tejas Upadhyay Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-12-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 89a85f193f3af..6718b7c2d1ea1 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -889,7 +889,9 @@ int xe_device_probe(struct xe_device *xe) if (err) goto err_unregister_display; - xe_pmu_register(&xe->pmu); + err = xe_pmu_register(&xe->pmu); + if (err) + goto err_unregister_display; xe_debugfs_register(xe); From 62fbc75b28a7a2e8619c575d2a0acad595345ed1 Mon Sep 17 00:00:00 2001 From: Lucas De Marchi Date: Thu, 13 Feb 2025 11:29:09 -0800 Subject: [PATCH 117/130] drm/xe/hwmon: Stop ignoring errors on probe Not registering hwmon because it's not available (SRIOV_VF and DGFX) is different from failing the initialization. Handle the errors appropriately. Cc: Badal Nilawar Cc: Karthik Poosa Reviewed-by: Raag Jadav Reviewed-by: Badal Nilawar Link: https://patchwork.freedesktop.org/patch/msgid/20250213192909.996148-13-lucas.demarchi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 4 +++- drivers/gpu/drm/xe/xe_hwmon.c | 31 ++++++++++++++++--------------- drivers/gpu/drm/xe/xe_hwmon.h | 4 ++-- 3 files changed, 21 insertions(+), 18 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 6718b7c2d1ea1..91525299494ed 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -895,7 +895,9 @@ int xe_device_probe(struct xe_device *xe) xe_debugfs_register(xe); - xe_hwmon_register(xe); + err = xe_hwmon_register(xe); + if (err) + goto err_unregister_display; for_each_gt(gt, xe, id) xe_gt_sanitize_freq(gt); diff --git a/drivers/gpu/drm/xe/xe_hwmon.c b/drivers/gpu/drm/xe/xe_hwmon.c index 7f327e3342123..48d80ffdf7bb9 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.c +++ b/drivers/gpu/drm/xe/xe_hwmon.c @@ -839,10 +839,9 @@ static const struct hwmon_chip_info hwmon_chip_info = { }; static void -xe_hwmon_get_preregistration_info(struct xe_device *xe) +xe_hwmon_get_preregistration_info(struct xe_hwmon *hwmon) { - struct xe_mmio *mmio = xe_root_tile_mmio(xe); - struct xe_hwmon *hwmon = xe->hwmon; + struct xe_mmio *mmio = xe_root_tile_mmio(hwmon->xe); long energy; u64 val_sku_unit = 0; int channel; @@ -876,33 +875,34 @@ static void xe_hwmon_mutex_destroy(void *arg) mutex_destroy(&hwmon->hwmon_lock); } -void xe_hwmon_register(struct xe_device *xe) +int xe_hwmon_register(struct xe_device *xe) { struct device *dev = xe->drm.dev; struct xe_hwmon *hwmon; + int ret; /* hwmon is available only for dGfx */ if (!IS_DGFX(xe)) - return; + return 0; /* hwmon is not available on VFs */ if (IS_SRIOV_VF(xe)) - return; + return 0; hwmon = devm_kzalloc(dev, sizeof(*hwmon), GFP_KERNEL); if (!hwmon) - return; - - xe->hwmon = hwmon; + return -ENOMEM; mutex_init(&hwmon->hwmon_lock); - if (devm_add_action_or_reset(dev, xe_hwmon_mutex_destroy, hwmon)) - return; + ret = devm_add_action_or_reset(dev, xe_hwmon_mutex_destroy, hwmon); + if (ret) + return ret; /* There's only one instance of hwmon per device */ hwmon->xe = xe; + xe->hwmon = hwmon; - xe_hwmon_get_preregistration_info(xe); + xe_hwmon_get_preregistration_info(hwmon); drm_dbg(&xe->drm, "Register xe hwmon interface\n"); @@ -910,11 +910,12 @@ void xe_hwmon_register(struct xe_device *xe) hwmon->hwmon_dev = devm_hwmon_device_register_with_info(dev, "xe", hwmon, &hwmon_chip_info, hwmon_groups); - if (IS_ERR(hwmon->hwmon_dev)) { - drm_warn(&xe->drm, "Failed to register xe hwmon (%pe)\n", hwmon->hwmon_dev); + drm_err(&xe->drm, "Failed to register xe hwmon (%pe)\n", hwmon->hwmon_dev); xe->hwmon = NULL; - return; + return PTR_ERR(hwmon->hwmon_dev); } + + return 0; } diff --git a/drivers/gpu/drm/xe/xe_hwmon.h b/drivers/gpu/drm/xe/xe_hwmon.h index c42a1de2cd7a2..d02c1bfe8c0a0 100644 --- a/drivers/gpu/drm/xe/xe_hwmon.h +++ b/drivers/gpu/drm/xe/xe_hwmon.h @@ -11,9 +11,9 @@ struct xe_device; #if IS_REACHABLE(CONFIG_HWMON) -void xe_hwmon_register(struct xe_device *xe); +int xe_hwmon_register(struct xe_device *xe); #else -static inline void xe_hwmon_register(struct xe_device *xe) { }; +static inline int xe_hwmon_register(struct xe_device *xe) { return 0; }; #endif #endif /* _XE_HWMON_H_ */ From 611160b02a40ce3f60ab94eea85b394dca1cafd2 Mon Sep 17 00:00:00 2001 From: Michal Wajdeczko Date: Tue, 11 Feb 2025 16:50:34 +0100 Subject: [PATCH 118/130] drm/xe/pf: Release all VFs configs on device removal MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If we try to manually provision VFs using debugfs and then we try to unload the driver, we will see complains like: [ ] Memory manager not clean during takedown. [ ] RIP: 0010:drm_mm_takedown+0x3f/0x100 [ ] [drm:drm_mm_takedown] *ERROR* node [fedff000 + 00001000]: inserted at drm_mm_insert_node_in_range+0x2bd/0x520 xe_ggtt_node_insert+0x52/0x90 [xe] pf_provision_vf_ggtt+0x1fa/0xac0 [xe] xe_gt_sriov_pf_config_set_ggtt+0x79/0x7a0 [xe] ggtt_set+0x53/0x80 [xe] simple_attr_write_xsigned.isra.0+0xd2/0x150 simple_attr_write+0x14/0x30 debugfs_attr_write+0x4e/0x80 [ ] xe 0000:00:02.0: [drm] *ERROR* GT0: GUC ID manager unclean (1/65535) [ ] xe 0000:00:02.0: [drm] GT0: total 65535 [ ] xe 0000:00:02.0: [drm] GT0: used 1 [ ] xe 0000:00:02.0: [drm] GT0: range 65534..65534 (1) [ ] xe 0000:00:02.0: [drm] *ERROR* GT0: GuC doorbells manager unclean (1/256) [ ] xe 0000:00:02.0: [drm] GT0: count: 256 [ ] xe 0000:00:02.0: [drm] GT0: available range: 1..255 (255) [ ] xe 0000:00:02.0: [drm] GT0: available total: 255 [ ] xe 0000:00:02.0: [drm] GT0: reserved range: 0..0 (1) [ ] xe 0000:00:02.0: [drm] GT0: reserved total: 1 This could be easily fixed by adding config release action. Signed-off-by: Michal Wajdeczko Cc: Piotr Piórkowski Reviewed-by: Piotr Piórkowski Link: https://patchwork.freedesktop.org/patch/msgid/20250211155034.1028-1-michal.wajdeczko@intel.com --- drivers/gpu/drm/xe/xe_gt_sriov_pf.c | 6 +++++ drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c | 29 ++++++++++++++++++++++ drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h | 1 + 3 files changed, 36 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c index d66478deab989..c08efca6420e7 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf.c @@ -89,6 +89,12 @@ int xe_gt_sriov_pf_init_early(struct xe_gt *gt) */ int xe_gt_sriov_pf_init(struct xe_gt *gt) { + int err; + + err = xe_gt_sriov_pf_config_init(gt); + if (err) + return err; + return xe_gt_sriov_pf_migration_init(gt); } diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c index 88bd9d97ba5ca..10be109bf357f 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.c @@ -2356,6 +2356,35 @@ int xe_gt_sriov_pf_config_restore(struct xe_gt *gt, unsigned int vfid, return err; } +static void fini_config(void *arg) +{ + struct xe_gt *gt = arg; + struct xe_device *xe = gt_to_xe(gt); + unsigned int n, total_vfs = xe_sriov_pf_get_totalvfs(xe); + + mutex_lock(xe_gt_sriov_pf_master_mutex(gt)); + for (n = 1; n <= total_vfs; n++) + pf_release_vf_config(gt, n); + mutex_unlock(xe_gt_sriov_pf_master_mutex(gt)); +} + +/** + * xe_gt_sriov_pf_config_init - Initialize SR-IOV configuration data. + * @gt: the &xe_gt + * + * This function can only be called on PF. + * + * Return: 0 on success or a negative error code on failure. + */ +int xe_gt_sriov_pf_config_init(struct xe_gt *gt) +{ + struct xe_device *xe = gt_to_xe(gt); + + xe_gt_assert(gt, IS_SRIOV_PF(xe)); + + return devm_add_action_or_reset(xe->drm.dev, fini_config, gt); +} + /** * xe_gt_sriov_pf_config_restart - Restart SR-IOV configurations after a GT reset. * @gt: the &xe_gt diff --git a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h index f894e9d4abba2..513e6512a575b 100644 --- a/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h +++ b/drivers/gpu/drm/xe/xe_gt_sriov_pf_config.h @@ -63,6 +63,7 @@ int xe_gt_sriov_pf_config_restore(struct xe_gt *gt, unsigned int vfid, bool xe_gt_sriov_pf_config_is_empty(struct xe_gt *gt, unsigned int vfid); +int xe_gt_sriov_pf_config_init(struct xe_gt *gt); void xe_gt_sriov_pf_config_restart(struct xe_gt *gt); int xe_gt_sriov_pf_config_print_ggtt(struct xe_gt *gt, struct drm_printer *p); From b5fa0913b56cedf651884d47bac3f1cf6e7e5092 Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Thu, 13 Feb 2025 11:38:38 +0530 Subject: [PATCH 119/130] drm/xe: Fix typo in xe_job_ptrs %s/uinitialized/uninitialized/gc Reviewed-by: Satyanarayana K V P Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20250213060838.32493-1-tejas.upadhyay@intel.com Signed-off-by: Tejas Upadhyay --- drivers/gpu/drm/xe/xe_sched_job_types.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_sched_job_types.h b/drivers/gpu/drm/xe/xe_sched_job_types.h index d942b20a9f29c..dbf260dded8df 100644 --- a/drivers/gpu/drm/xe/xe_sched_job_types.h +++ b/drivers/gpu/drm/xe/xe_sched_job_types.h @@ -18,9 +18,9 @@ struct dma_fence_chain; * struct xe_job_ptrs - Per hw engine instance data */ struct xe_job_ptrs { - /** @lrc_fence: Pre-allocated uinitialized lrc fence.*/ + /** @lrc_fence: Pre-allocated uninitialized lrc fence.*/ struct dma_fence *lrc_fence; - /** @chain_fence: Pre-allocated ninitialized fence chain node. */ + /** @chain_fence: Pre-allocated uninitialized fence chain node. */ struct dma_fence_chain *chain_fence; /** @batch_addr: Batch buffer address. */ u64 batch_addr; From 339adeb10472a34bb74624958b031e490531d37c Mon Sep 17 00:00:00 2001 From: Maarten Lankhorst Date: Fri, 17 Jan 2025 12:53:05 +0100 Subject: [PATCH 120/130] drm/xe/display: Clarify XE_IOCTL_DBG message This should make it easier to understand from userspace why importing BO fails. Reviewed-by: Stuart Summers Link: https://patchwork.freedesktop.org/patch/msgid/20250117115305.53113-1-dev@lankhorst.se Signed-off-by: Maarten Lankhorst --- drivers/gpu/drm/xe/display/intel_fb_bo.c | 4 ++-- drivers/gpu/drm/xe/xe_bo.c | 16 ++++++++++++++++ drivers/gpu/drm/xe/xe_bo.h | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/xe/display/intel_fb_bo.c b/drivers/gpu/drm/xe/display/intel_fb_bo.c index 4d209ebc26c2a..b91eec05ce571 100644 --- a/drivers/gpu/drm/xe/display/intel_fb_bo.c +++ b/drivers/gpu/drm/xe/display/intel_fb_bo.c @@ -50,10 +50,10 @@ int intel_fb_bo_framebuffer_init(struct intel_framebuffer *intel_fb, /* * XE_BO_FLAG_SCANOUT should ideally be set at creation, or is * automatically set when creating FB. We cannot change caching - * mode when the boect is VM_BINDed, so we can only set + * mode when the bo is VM_BINDed, so we can only set * coherency with display when unbound. */ - if (XE_IOCTL_DBG(xe, !list_empty(&bo->ttm.base.gpuva.list))) { + if (XE_IOCTL_DBG(xe, xe_bo_is_vm_bound(bo))) { ttm_bo_unreserve(&bo->ttm); ret = -EINVAL; goto err; diff --git a/drivers/gpu/drm/xe/xe_bo.c b/drivers/gpu/drm/xe/xe_bo.c index 78d09c5ed26d1..25761924a8b41 100644 --- a/drivers/gpu/drm/xe/xe_bo.c +++ b/drivers/gpu/drm/xe/xe_bo.c @@ -128,6 +128,22 @@ bool xe_bo_is_stolen_devmem(struct xe_bo *bo) GRAPHICS_VERx100(xe_bo_device(bo)) >= 1270; } +/** + * xe_bo_is_vm_bound - check if BO has any mappings through VM_BIND + * @bo: The BO + * + * Check if a given bo is bound through VM_BIND. This requires the + * reservation lock for the BO to be held. + * + * Returns: boolean + */ +bool xe_bo_is_vm_bound(struct xe_bo *bo) +{ + xe_bo_assert_held(bo); + + return !list_empty(&bo->ttm.base.gpuva.list); +} + static bool xe_bo_is_user(struct xe_bo *bo) { return bo->flags & XE_BO_FLAG_USER; diff --git a/drivers/gpu/drm/xe/xe_bo.h b/drivers/gpu/drm/xe/xe_bo.h index f09b9315721b4..a25340949415a 100644 --- a/drivers/gpu/drm/xe/xe_bo.h +++ b/drivers/gpu/drm/xe/xe_bo.h @@ -241,6 +241,7 @@ bool mem_type_is_vram(u32 mem_type); bool xe_bo_is_vram(struct xe_bo *bo); bool xe_bo_is_stolen(struct xe_bo *bo); bool xe_bo_is_stolen_devmem(struct xe_bo *bo); +bool xe_bo_is_vm_bound(struct xe_bo *bo); bool xe_bo_has_single_placement(struct xe_bo *bo); uint64_t vram_region_gpu_offset(struct ttm_resource *res); From 5bee1e2de39fe41be132ee389529407212894582 Mon Sep 17 00:00:00 2001 From: Ilia Levi Date: Thu, 30 Jan 2025 12:50:56 +0200 Subject: [PATCH 121/130] drm/xe: s/xe_mmio_init/xe_mmio_probe_early Rename so that xe_mmio_init() can be used in subsequent patches to initialize an instance of struct xe_mmio. Signed-off-by: Ilia Levi Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20250130105057.136586-1-ilia.levi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/xe_device.c | 2 +- drivers/gpu/drm/xe/xe_mmio.c | 6 +++--- drivers/gpu/drm/xe/xe_mmio.h | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_device.c b/drivers/gpu/drm/xe/xe_device.c index 91525299494ed..06ccff1450508 100644 --- a/drivers/gpu/drm/xe/xe_device.c +++ b/drivers/gpu/drm/xe/xe_device.c @@ -692,7 +692,7 @@ int xe_device_probe_early(struct xe_device *xe) { int err; - err = xe_mmio_init(xe); + err = xe_mmio_probe_early(xe); if (err) return err; diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index d321a21aacf02..3aed849a128b6 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -60,7 +60,7 @@ static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) /* * Nothing to be done as tile 0 has already been setup earlier with the - * entire BAR mapped - see xe_mmio_init() + * entire BAR mapped - see xe_mmio_probe_early() */ if (xe->info.tile_count == 1) return; @@ -74,7 +74,7 @@ static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) /* * Although the per-tile mmio regs are not yet initialized, this * is fine as it's going to the root tile's mmio, that's - * guaranteed to be initialized earlier in xe_mmio_init() + * guaranteed to be initialized earlier in xe_mmio_probe_early() */ mtcfg = xe_mmio_read64_2x32(mmio, XEHP_MTCFG_ADDR); tile_count = REG_FIELD_GET(TILE_COUNT, mtcfg) + 1; @@ -122,7 +122,7 @@ static void mmio_fini(void *arg) root_tile->mmio.regs = NULL; } -int xe_mmio_init(struct xe_device *xe) +int xe_mmio_probe_early(struct xe_device *xe) { struct xe_tile *root_tile = xe_device_get_root_tile(xe); struct pci_dev *pdev = to_pci_dev(xe->drm.dev); diff --git a/drivers/gpu/drm/xe/xe_mmio.h b/drivers/gpu/drm/xe/xe_mmio.h index 8a46f4006a84f..b32e7ee4b23e5 100644 --- a/drivers/gpu/drm/xe/xe_mmio.h +++ b/drivers/gpu/drm/xe/xe_mmio.h @@ -11,7 +11,7 @@ struct xe_device; struct xe_reg; -int xe_mmio_init(struct xe_device *xe); +int xe_mmio_probe_early(struct xe_device *xe); int xe_mmio_probe_tiles(struct xe_device *xe); u8 xe_mmio_read8(struct xe_mmio *mmio, struct xe_reg reg); From eb79d71e506a1caeb0dedd1bab0e6899e8e74f5b Mon Sep 17 00:00:00 2001 From: Ilia Levi Date: Thu, 13 Feb 2025 11:35:59 +0200 Subject: [PATCH 122/130] drm/xe: Add xe_mmio_init() initialization function Add a convenience function for minimal initialization of struct xe_mmio. This function also validates that the entirety of the provided mmio region is usable with struct xe_reg. v2: Modify commit message, add kernel doc, refactor assert (Michal) v3: Fix off-by-one bug, add clarifying macro (Michal) v4: Derive bitfield width from size (Michal) Signed-off-by: Ilia Levi Reviewed-by: Michal Wajdeczko Reviewed-by: Lucas De Marchi Link: https://patchwork.freedesktop.org/patch/msgid/20250213093559.204652-1-ilia.levi@intel.com Signed-off-by: Lucas De Marchi --- drivers/gpu/drm/xe/regs/xe_reg_defs.h | 14 +++++++++++- drivers/gpu/drm/xe/xe_gt.c | 7 +++--- drivers/gpu/drm/xe/xe_mmio.c | 32 ++++++++++++++++++--------- drivers/gpu/drm/xe/xe_mmio.h | 2 ++ 4 files changed, 39 insertions(+), 16 deletions(-) diff --git a/drivers/gpu/drm/xe/regs/xe_reg_defs.h b/drivers/gpu/drm/xe/regs/xe_reg_defs.h index 89716172fbb85..c39aab843e357 100644 --- a/drivers/gpu/drm/xe/regs/xe_reg_defs.h +++ b/drivers/gpu/drm/xe/regs/xe_reg_defs.h @@ -7,9 +7,21 @@ #define _XE_REG_DEFS_H_ #include +#include +#include #include "compat-i915-headers/i915_reg_defs.h" +/** + * XE_REG_ADDR_MAX - The upper limit on MMIO register address + * + * This macro specifies the upper limit (not inclusive) on MMIO register offset + * supported by struct xe_reg and functions based on struct xe_mmio. + * + * Currently this is defined as 4 MiB. + */ +#define XE_REG_ADDR_MAX SZ_4M + /** * struct xe_reg - Register definition * @@ -21,7 +33,7 @@ struct xe_reg { union { struct { /** @addr: address */ - u32 addr:22; + u32 addr:const_ilog2(XE_REG_ADDR_MAX); /** * @masked: register is "masked", with upper 16bits used * to identify the bits that are updated on the lower diff --git a/drivers/gpu/drm/xe/xe_gt.c b/drivers/gpu/drm/xe/xe_gt.c index bd16ca070dd20..650a0ee56e97e 100644 --- a/drivers/gpu/drm/xe/xe_gt.c +++ b/drivers/gpu/drm/xe/xe_gt.c @@ -626,10 +626,9 @@ int xe_gt_init(struct xe_gt *gt) void xe_gt_mmio_init(struct xe_gt *gt) { struct xe_tile *tile = gt_to_tile(gt); + struct xe_device *xe = tile_to_xe(tile); - gt->mmio.regs = tile->mmio.regs; - gt->mmio.regs_size = tile->mmio.regs_size; - gt->mmio.tile = tile; + xe_mmio_init(>->mmio, tile, tile->mmio.regs, tile->mmio.regs_size); if (gt->info.type == XE_GT_TYPE_MEDIA) { gt->mmio.adj_offset = MEDIA_GT_GSI_OFFSET; @@ -639,7 +638,7 @@ void xe_gt_mmio_init(struct xe_gt *gt) gt->mmio.adj_limit = 0; } - if (IS_SRIOV_VF(gt_to_xe(gt))) + if (IS_SRIOV_VF(xe)) gt->mmio.sriov_vf_gt = gt; } diff --git a/drivers/gpu/drm/xe/xe_mmio.c b/drivers/gpu/drm/xe/xe_mmio.c index 3aed849a128b6..70a36e7775466 100644 --- a/drivers/gpu/drm/xe/xe_mmio.c +++ b/drivers/gpu/drm/xe/xe_mmio.c @@ -55,7 +55,6 @@ static void tiles_fini(void *arg) static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) { struct xe_tile *tile; - void __iomem *regs; u8 id; /* @@ -94,13 +93,8 @@ static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) } } - regs = xe->mmio.regs; - for_each_tile(tile, xe, id) { - tile->mmio.regs_size = SZ_4M; - tile->mmio.regs = regs; - tile->mmio.tile = tile; - regs += tile_mmio_size; - } + for_each_remote_tile(tile, xe, id) + xe_mmio_init(&tile->mmio, tile, xe->mmio.regs + id * tile_mmio_size, SZ_4M); } int xe_mmio_probe_tiles(struct xe_device *xe) @@ -140,13 +134,29 @@ int xe_mmio_probe_early(struct xe_device *xe) } /* Setup first tile; other tiles (if present) will be setup later. */ - root_tile->mmio.regs_size = SZ_4M; - root_tile->mmio.regs = xe->mmio.regs; - root_tile->mmio.tile = root_tile; + xe_mmio_init(&root_tile->mmio, root_tile, xe->mmio.regs, SZ_4M); return devm_add_action_or_reset(xe->drm.dev, mmio_fini, xe); } +/** + * xe_mmio_init() - Initialize an MMIO instance + * @mmio: Pointer to the MMIO instance to initialize + * @tile: The tile to which the MMIO region belongs + * @ptr: Pointer to the start of the MMIO region + * @size: The size of the MMIO region in bytes + * + * This is a convenience function for minimal initialization of struct xe_mmio. + */ +void xe_mmio_init(struct xe_mmio *mmio, struct xe_tile *tile, void __iomem *ptr, u32 size) +{ + xe_tile_assert(tile, size <= XE_REG_ADDR_MAX); + + mmio->regs = ptr; + mmio->regs_size = size; + mmio->tile = tile; +} + static void mmio_flush_pending_writes(struct xe_mmio *mmio) { #define DUMMY_REG_OFFSET 0x130030 diff --git a/drivers/gpu/drm/xe/xe_mmio.h b/drivers/gpu/drm/xe/xe_mmio.h index b32e7ee4b23e5..c151ba569003f 100644 --- a/drivers/gpu/drm/xe/xe_mmio.h +++ b/drivers/gpu/drm/xe/xe_mmio.h @@ -14,6 +14,8 @@ struct xe_reg; int xe_mmio_probe_early(struct xe_device *xe); int xe_mmio_probe_tiles(struct xe_device *xe); +void xe_mmio_init(struct xe_mmio *mmio, struct xe_tile *tile, void __iomem *ptr, u32 size); + u8 xe_mmio_read8(struct xe_mmio *mmio, struct xe_reg reg); u16 xe_mmio_read16(struct xe_mmio *mmio, struct xe_reg reg); void xe_mmio_write32(struct xe_mmio *mmio, struct xe_reg reg, u32 val); From ceb33b9de14aeab9bdbf73a45f44013d1e2aef34 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 17 Feb 2025 15:01:33 -0500 Subject: [PATCH 123/130] drm/{i915, xe}/display: Move dsm registration under intel_driver Move dsm register/unregister calls from the drivers to under intel_display_driver register/unregister. v2: Rebase only Reviewed-by: Jonathan Cavitt Link: https://patchwork.freedesktop.org/patch/msgid/20250217200133.741758-1-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/i915/display/intel_display_driver.c | 4 ++++ drivers/gpu/drm/i915/i915_driver.c | 5 ----- drivers/gpu/drm/xe/display/xe_display.c | 2 -- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/drivers/gpu/drm/i915/display/intel_display_driver.c b/drivers/gpu/drm/i915/display/intel_display_driver.c index 1aa0b298c278d..20104c88ffdb2 100644 --- a/drivers/gpu/drm/i915/display/intel_display_driver.c +++ b/drivers/gpu/drm/i915/display/intel_display_driver.c @@ -566,6 +566,8 @@ void intel_display_driver_register(struct intel_display *display) intel_display_device_info_print(DISPLAY_INFO(display), DISPLAY_RUNTIME_INFO(display), &p); + + intel_register_dsm_handler(); } /* part #1: call before irq uninstall */ @@ -643,6 +645,8 @@ void intel_display_driver_unregister(struct intel_display *display) if (!HAS_DISPLAY(display)) return; + intel_unregister_dsm_handler(); + drm_client_dev_unregister(display->drm); /* diff --git a/drivers/gpu/drm/i915/i915_driver.c b/drivers/gpu/drm/i915/i915_driver.c index c2ae37d6b94d5..ce163f58fd766 100644 --- a/drivers/gpu/drm/i915/i915_driver.c +++ b/drivers/gpu/drm/i915/i915_driver.c @@ -46,7 +46,6 @@ #include #include "display/i9xx_display_sr.h" -#include "display/intel_acpi.h" #include "display/intel_bw.h" #include "display/intel_cdclk.h" #include "display/intel_crtc.h" @@ -657,8 +656,6 @@ static void i915_driver_register(struct drm_i915_private *dev_priv) intel_power_domains_enable(display); intel_runtime_pm_enable(&dev_priv->runtime_pm); - intel_register_dsm_handler(); - if (i915_switcheroo_register(dev_priv)) drm_err(&dev_priv->drm, "Failed to register vga switcheroo!\n"); } @@ -675,8 +672,6 @@ static void i915_driver_unregister(struct drm_i915_private *dev_priv) i915_switcheroo_unregister(dev_priv); - intel_unregister_dsm_handler(); - intel_runtime_pm_disable(&dev_priv->runtime_pm); intel_power_domains_disable(display); diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index ac0804726e550..215a50061485a 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -196,7 +196,6 @@ void xe_display_register(struct xe_device *xe) intel_display_driver_register(display); intel_power_domains_enable(display); - intel_register_dsm_handler(); } void xe_display_unregister(struct xe_device *xe) @@ -206,7 +205,6 @@ void xe_display_unregister(struct xe_device *xe) if (!xe->info.probe_display) return; - intel_unregister_dsm_handler(); intel_power_domains_disable(display); intel_display_driver_unregister(display); } From f2cd50990d210eb70bf38d8077836772d4216a36 Mon Sep 17 00:00:00 2001 From: Rodrigo Vivi Date: Mon, 17 Feb 2025 20:03:30 -0500 Subject: [PATCH 124/130] drm/xe/display: Spin-off xe_display runtime/d3cold sequences No functional change. This patch only splits the xe_display_pm suspend/resume functions in the regular suspend/resume from the runtime/d3cold ones. v2: - Rename d3cold functions (Jonathan) - Rebase Reviewed-by: Jonathan Cavitt Link: https://patchwork.freedesktop.org/patch/msgid/20250218010330.761340-1-rodrigo.vivi@intel.com Signed-off-by: Rodrigo Vivi --- drivers/gpu/drm/xe/display/xe_display.c | 87 +++++++++++++++++-------- 1 file changed, 59 insertions(+), 28 deletions(-) diff --git a/drivers/gpu/drm/xe/display/xe_display.c b/drivers/gpu/drm/xe/display/xe_display.c index 215a50061485a..7fef78f5606df 100644 --- a/drivers/gpu/drm/xe/display/xe_display.c +++ b/drivers/gpu/drm/xe/display/xe_display.c @@ -288,11 +288,58 @@ static void xe_display_flush_cleanup_work(struct xe_device *xe) } } -/* TODO: System and runtime suspend/resume sequences will be sanitized as a follow-up. */ -static void __xe_display_pm_suspend(struct xe_device *xe, bool runtime) +static void xe_display_enable_d3cold(struct xe_device *xe) +{ + struct intel_display *display = &xe->display; + + if (!xe->info.probe_display) + return; + + /* + * We do a lot of poking in a lot of registers, make sure they work + * properly. + */ + intel_power_domains_disable(display); + + xe_display_flush_cleanup_work(xe); + + intel_opregion_suspend(display, PCI_D3cold); + + intel_dmc_suspend(display); + + if (has_display(xe)) + intel_hpd_poll_enable(xe); +} + +static void xe_display_disable_d3cold(struct xe_device *xe) +{ + struct intel_display *display = &xe->display; + + if (!xe->info.probe_display) + return; + + intel_dmc_resume(display); + + if (has_display(xe)) + drm_mode_config_reset(&xe->drm); + + intel_display_driver_init_hw(display); + + intel_hpd_init(xe); + + if (has_display(xe)) + intel_hpd_poll_disable(xe); + + intel_opregion_resume(display); + + intel_power_domains_enable(display); +} + +void xe_display_pm_suspend(struct xe_device *xe) { struct intel_display *display = &xe->display; bool s2idle = suspend_to_idle(); + if (!xe->info.probe_display) return; @@ -301,10 +348,9 @@ static void __xe_display_pm_suspend(struct xe_device *xe, bool runtime) * properly. */ intel_power_domains_disable(display); - if (!runtime) - intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_SUSPENDED, true); + intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_SUSPENDED, true); - if (!runtime && has_display(xe)) { + if (has_display(xe)) { drm_kms_helper_poll_disable(&xe->drm); intel_display_driver_disable_user_access(display); intel_display_driver_suspend(display); @@ -312,10 +358,9 @@ static void __xe_display_pm_suspend(struct xe_device *xe, bool runtime) xe_display_flush_cleanup_work(xe); - if (!runtime) - intel_hpd_cancel_work(xe); + intel_hpd_cancel_work(xe); - if (!runtime && has_display(xe)) { + if (has_display(xe)) { intel_display_driver_suspend_access(display); intel_encoder_suspend_all(&xe->display); } @@ -323,14 +368,6 @@ static void __xe_display_pm_suspend(struct xe_device *xe, bool runtime) intel_opregion_suspend(display, s2idle ? PCI_D1 : PCI_D3cold); intel_dmc_suspend(display); - - if (runtime && has_display(xe)) - intel_hpd_poll_enable(xe); -} - -void xe_display_pm_suspend(struct xe_device *xe) -{ - __xe_display_pm_suspend(xe, false); } void xe_display_pm_shutdown(struct xe_device *xe) @@ -369,7 +406,7 @@ void xe_display_pm_runtime_suspend(struct xe_device *xe) return; if (xe->d3cold.allowed) { - __xe_display_pm_suspend(xe, true); + xe_display_enable_d3cold(xe); return; } @@ -430,7 +467,7 @@ void xe_display_pm_resume_early(struct xe_device *xe) intel_display_power_resume_early(display); } -static void __xe_display_pm_resume(struct xe_device *xe, bool runtime) +void xe_display_pm_resume(struct xe_device *xe) { struct intel_display *display = &xe->display; @@ -444,12 +481,12 @@ static void __xe_display_pm_resume(struct xe_device *xe, bool runtime) intel_display_driver_init_hw(display); - if (!runtime && has_display(xe)) + if (has_display(xe)) intel_display_driver_resume_access(display); intel_hpd_init(xe); - if (!runtime && has_display(xe)) { + if (has_display(xe)) { intel_display_driver_resume(display); drm_kms_helper_poll_enable(&xe->drm); intel_display_driver_enable_user_access(display); @@ -460,24 +497,18 @@ static void __xe_display_pm_resume(struct xe_device *xe, bool runtime) intel_opregion_resume(display); - if (!runtime) - intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_RUNNING, false); + intel_fbdev_set_suspend(&xe->drm, FBINFO_STATE_RUNNING, false); intel_power_domains_enable(display); } -void xe_display_pm_resume(struct xe_device *xe) -{ - __xe_display_pm_resume(xe, false); -} - void xe_display_pm_runtime_resume(struct xe_device *xe) { if (!xe->info.probe_display) return; if (xe->d3cold.allowed) { - __xe_display_pm_resume(xe, true); + xe_display_disable_d3cold(xe); return; } From a1e5b6d83e03d60d15ba393cbbd7d5c13e5cf0b3 Mon Sep 17 00:00:00 2001 From: Matt Roper Date: Tue, 18 Feb 2025 12:05:12 -0800 Subject: [PATCH 125/130] drm/xe: Drop unnecessary GT lookup in xe_exec_queue_create_ioctl() xe_exec_queue_create_ioctl() performs a lookup of the xe_gt for the GT ID passed from userspace, but the result is never actually used. Since there's already a separate (and earlier) check that the ID passed from userspace is valid, the unnecessary lookup can be removed. Reviewed-by: Jonathan Cavitt Reviewed-by: Ashutosh Dixit Link: https://patchwork.freedesktop.org/patch/msgid/20250218200511.4050060-2-matthew.d.roper@intel.com Signed-off-by: Matt Roper --- drivers/gpu/drm/xe/xe_exec_queue.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/xe/xe_exec_queue.c b/drivers/gpu/drm/xe/xe_exec_queue.c index 6051db78d7065..23a9f519ce1c7 100644 --- a/drivers/gpu/drm/xe/xe_exec_queue.c +++ b/drivers/gpu/drm/xe/xe_exec_queue.c @@ -539,7 +539,7 @@ static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue return 0; } -static u32 calc_validate_logical_mask(struct xe_device *xe, struct xe_gt *gt, +static u32 calc_validate_logical_mask(struct xe_device *xe, struct drm_xe_engine_class_instance *eci, u16 width, u16 num_placements) { @@ -601,7 +601,6 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, u64_to_user_ptr(args->instances); struct xe_hw_engine *hwe; struct xe_vm *vm; - struct xe_gt *gt; struct xe_tile *tile; struct xe_exec_queue *q = NULL; u32 logical_mask; @@ -654,8 +653,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, &q->multi_gt_link); } } else { - gt = xe_device_get_gt(xe, eci[0].gt_id); - logical_mask = calc_validate_logical_mask(xe, gt, eci, + logical_mask = calc_validate_logical_mask(xe, eci, args->width, args->num_placements); if (XE_IOCTL_DBG(xe, !logical_mask)) From 5a9f8db2db70e09b47010a936b6c4fb83975464f Mon Sep 17 00:00:00 2001 From: Marcin Bernatowicz Date: Wed, 5 Feb 2025 20:16:43 +0100 Subject: [PATCH 126/130] drm/xe/vf: Return EOPNOTSUPP for DRM_XE_DEVICE_QUERY_ENGINE_CYCLES if VF MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RING_TIMESTAMP registers are not available for VF (Virtual Function) drivers. Return -EOPNOTSUPP when the DRM_XE_DEVICE_QUERY_ENGINE_CYCLES ioctl is invoked on a VF device. Signed-off-by: Marcin Bernatowicz Cc: Michal Wajdeczko Cc: Michał Winiarski Cc: Umesh Nerlige Ramappa Reviewed-by: Satyanarayana K V P Signed-off-by: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/20250205191644.2550879-2-marcin.bernatowicz@linux.intel.com --- drivers/gpu/drm/xe/xe_query.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_query.c b/drivers/gpu/drm/xe/xe_query.c index 042f87a688e75..ebfae746f8613 100644 --- a/drivers/gpu/drm/xe/xe_query.c +++ b/drivers/gpu/drm/xe/xe_query.c @@ -121,6 +121,9 @@ query_engine_cycles(struct xe_device *xe, struct xe_gt *gt; unsigned int fw_ref; + if (IS_SRIOV_VF(xe)) + return -EOPNOTSUPP; + if (query->size == 0) { query->size = size; return 0; From 94030a1d3283251778411cf74553607a65260f78 Mon Sep 17 00:00:00 2001 From: Marcin Bernatowicz Date: Wed, 5 Feb 2025 20:16:44 +0100 Subject: [PATCH 127/130] drm/xe/client: Skip show_run_ticks if unable to read timestamp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit RING_TIMESTAMP registers are inaccessible in VF mode. Without drm-total-cycles-*, other keys provide little value. Skip all optional "run_ticks" keys in this case. Signed-off-by: Marcin Bernatowicz Cc: Lucas De Marchi Cc: Michal Wajdeczko Cc: Michał Winiarski Cc: Umesh Nerlige Ramappa Reviewed-by: Satyanarayana K V P Signed-off-by: Michal Wajdeczko Link: https://patchwork.freedesktop.org/patch/msgid/20250205191644.2550879-3-marcin.bernatowicz@linux.intel.com --- drivers/gpu/drm/xe/xe_drm_client.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/gpu/drm/xe/xe_drm_client.c b/drivers/gpu/drm/xe/xe_drm_client.c index 2d4874d2b9225..31f688e953d7b 100644 --- a/drivers/gpu/drm/xe/xe_drm_client.c +++ b/drivers/gpu/drm/xe/xe_drm_client.c @@ -324,6 +324,14 @@ static void show_run_ticks(struct drm_printer *p, struct drm_file *file) u64 gpu_timestamp; unsigned int fw_ref; + /* + * RING_TIMESTAMP registers are inaccessible in VF mode. + * Without drm-total-cycles-*, other keys provide little value. + * Show all or none of the optional "run_ticks" keys in this case. + */ + if (IS_SRIOV_VF(xe)) + return; + /* * Wait for any exec queue going away: their cycles will get updated on * context switch out, so wait for that to happen From 70c7273778bf7f18f2e46a41638f6ff38fb9fa51 Mon Sep 17 00:00:00 2001 From: Priyanka Dandamudi Date: Wed, 12 Feb 2025 09:32:12 +0000 Subject: [PATCH 128/130] drm/xe: Add fault injection for xe_sync_entry_parse Add fault injection for xe_sync_entry_parse to allow it to fail while executing xe_vm_bind_ioctl(). This needs to be added as it cannot be reached by injecting error through IOCTL arguments. Signed-off-by: Priyanka Dandamudi Reviewed-by: Satyanarayana K V P Reviewed-by: Himal Prasad Ghimiray Link: https://patchwork.freedesktop.org/patch/msgid/20250212093212.3069356-1-priyanka.dandamudi@intel.com Signed-off-by: Himal Prasad Ghimiray --- drivers/gpu/drm/xe/xe_sync.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_sync.c b/drivers/gpu/drm/xe/xe_sync.c index 42f5bebd09e50..f87276df18f28 100644 --- a/drivers/gpu/drm/xe/xe_sync.c +++ b/drivers/gpu/drm/xe/xe_sync.c @@ -210,6 +210,7 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef, return 0; } +ALLOW_ERROR_INJECTION(xe_sync_entry_parse, ERRNO); int xe_sync_entry_add_deps(struct xe_sync_entry *sync, struct xe_sched_job *job) { From 98c9d27ab30aa9c6451d3a34e6e297171f273e51 Mon Sep 17 00:00:00 2001 From: Umesh Nerlige Ramappa Date: Tue, 11 Feb 2025 17:02:55 -0800 Subject: [PATCH 129/130] drm/xe/oa: Ensure that polled read returns latest data In polled mode, user calls poll() for read data to be available before performing a read(). In the duration between these 2 calls, there may be new data available in the OA buffer. To ensure user reads all available data, check for latest data in the OA buffer in polled read. Signed-off-by: Umesh Nerlige Ramappa Reviewed-by: Ashutosh Dixit Link: https://patchwork.freedesktop.org/patch/msgid/20250212010255.1423343-1-umesh.nerlige.ramappa@intel.com --- drivers/gpu/drm/xe/xe_oa.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/gpu/drm/xe/xe_oa.c b/drivers/gpu/drm/xe/xe_oa.c index d89e6cabf5a56..2c5a24a13e87a 100644 --- a/drivers/gpu/drm/xe/xe_oa.c +++ b/drivers/gpu/drm/xe/xe_oa.c @@ -548,6 +548,7 @@ static ssize_t xe_oa_read(struct file *file, char __user *buf, mutex_unlock(&stream->stream_lock); } while (!offset && !ret); } else { + xe_oa_buffer_check_unlocked(stream); mutex_lock(&stream->stream_lock); ret = __xe_oa_read(stream, buf, count, &offset); mutex_unlock(&stream->stream_lock); From b7b68c6e36776a46d47743bc53b19089f5e0029a Mon Sep 17 00:00:00 2001 From: Tejas Upadhyay Date: Fri, 21 Feb 2025 17:23:44 +0530 Subject: [PATCH 130/130] drm/xe/wa: Limit char per line to 100 Above 100 char per line checkpatch would complain. Fixing it. Reviewed-by: Badal Nilawar Link: https://patchwork.freedesktop.org/patch/msgid/20250221115344.389975-1-tejas.upadhyay@intel.com Signed-off-by: Tejas Upadhyay --- drivers/gpu/drm/xe/xe_wa.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/gpu/drm/xe/xe_wa.c b/drivers/gpu/drm/xe/xe_wa.c index 744dba4fdb58b..d4982799383cc 100644 --- a/drivers/gpu/drm/xe/xe_wa.c +++ b/drivers/gpu/drm/xe/xe_wa.c @@ -599,7 +599,8 @@ static const struct xe_rtp_entry_sr engine_was[] = { /* Xe3_LPG */ { XE_RTP_NAME("14021402888"), - XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3001), FUNC(xe_rtp_match_first_render_or_compute)), + XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3001), + FUNC(xe_rtp_match_first_render_or_compute)), XE_RTP_ACTIONS(SET(HALF_SLICE_CHICKEN7, CLEAR_OPTIMIZATION_DISABLE)) }, { XE_RTP_NAME("18034896535"),