drm-xe-next for 6.12 UAPI Changes: - Rename xe perf layer as xe observation layer, but was also made available via fixes to previous verison (Ashutosh) - Use write-back caching mode for system memory on DGFX, but was also mad available via fixes to previous version (Thomas) - Expose SIMD16 EU mask in topology query for userspace to know the type of EU, as available in PVC, Lunar Lake and Battlemage (Lucas) - Return ENOBUFS instead of ENOMEM in vm_bind if failure is tied to an array of binds (Matthew Brost) Driver Changes: - Log cleanup moving messages to debug priority (Michal Wajdeczko) - Add timeout to fences to adhere to dma_buf rules (Matthew Brost) - Rename old engine nomenclature to exec_queue (Matthew Brost) - Convert multiple bind ops to 1 job (Matthew Brost) - Add error injection for vm bind to help testing error path (Matthew Brost) - Fix error handling in page table to propagate correctly to userspace (Matthew Brost) - Re-organize and cleanup SR-IOV related registers (Michal Wajdeczko) - Make the device write barrier compatible with VF (Michal Wajdeczko) - New display workarounds for Battlemage (Matthew Auld) - New media workarounds for Lunar Lake and Battlemage (Ngai-Mint Kwan) - New graphics workarounds for Lunar Lake (Bommu Krishnaiah) - Tracepoint updates (Matthew Brost, Nirmoy Das) - Cleanup the header generation for OOB workarounds (Lucas De Marchi) - Fix leaking HDCP-related object (Nirmoy Das) - Serialize L2 flushes to avoid races (Tejas Upadhyay) - Log pid and comm on job timeout (José Roberto de Souza) - Simplify boilerplate code for live kunit (Michal Wajdeczko) - Improve kunit skips for live kunit (Michal Wajdeczko) - Fix xe_sync cleanup when handling xe_exec ioctl (Ashutosh Dixit) - Limit fair VF LMEM provisioning (Michal Wajdeczko) - New workaround to fence mmio writes in Lunar Lake (Tejas Upadhyay) - Warn on writes inaccessible register in VF (Michal Wajdeczko) - Fix register lookup in VF (Michal Wajdeczko) - Add GSC support for Battlemage (Alexander Usyskin) - Fix wedging only the GT in which timeout occurred (Matthew Brost) - Block device suspend when wedging (Matthew Brost) - Handle compression and migration changes for Battlemage (Akshata Jahagirdar) - Limit access of stolen memory for Lunar Lake (Uma Shankar) - Fail invalid addresses during user fence creation (Matthew Brost) - Refcount xe_file to safely and accurately store fdinfo stats (Umesh Nerlige Ramappa) - Cleanup and fix PM reference for TLB invalidation code (Matthew Brost) - Fix PM reference handling when communicating with GuC (Matthew Brost) - Add new BO flag for 2 MiB alignement and use in VF (Michal Wajdeczko) - Simplify MMIO setup for multi-tile platforms (Lucas De Marchi) - Add check for uninitialized access to OOB workarounds (Lucas De Marchi) - New GSC and HuC firmware blobs for Lunar Lake and Battlemage (Daniele Ceraolo Spurio) - Unify mmio wait logic (Gustavo Sousa) - Fix off-by-one when processing RTP rules (Lucas De Marchi) - Future-proof migrate logic with compressed PAT flag (Matt Roper) - Add WA kunit tests for Battlemage (Lucas De Marchi) - Test active tracking for workaorunds with kunit (Lucas De Marchi) - Add kunit tests for RTP with no actions (Lucas De Marchi) - Unify parse of OR rules in RTP (Lucas De Marchi) - Add performance tuning for Battlemage (Sai Teja Pottumuttu) - Make bit masks unsigned (Geert Uytterhoeven) Signed-off-by: Dave Airlie <airlied@redhat.com>
Unified · Split
| @@ -6,8 +6,16 @@ · 5 unmodified lines | ||
| 6 | 6 | #ifndef __INTEL_DISPLAY_WA_H__ |
| 7 | 7 | #define __INTEL_DISPLAY_WA_H__ |
| 8 | 8 | |
| 9 | +#include <linux/types.h> | |
| 10 | + | |
| 9 | 11 | struct drm_i915_private; |
| 10 | 12 | |
| 11 | 13 | void intel_display_wa_apply(struct drm_i915_private *i915); |
| 12 | 14 | |
| 15 | +#ifdef I915 | |
| 16 | +static inline bool intel_display_needs_wa_16023588340(struct drm_i915_private *i915) { return false; } | |
| 17 | +#else | |
| 18 | +bool intel_display_needs_wa_16023588340(struct drm_i915_private *i915); | |
| 19 | +#endif | |
| 20 | + | |
| 13 | 21 | #endif |
| @@ -56,6 +56,7 @@ · 55 unmodified lines | ||
| 56 | 56 | #include "intel_display_device.h" |
| 57 | 57 | #include "intel_display_trace.h" |
| 58 | 58 | #include "intel_display_types.h" |
| 59 | +#include "intel_display_wa.h" | |
| 59 | 60 | #include "intel_fbc.h" |
| 60 | 61 | #include "intel_fbc_regs.h" |
| 61 | 62 | #include "intel_frontbuffer.h" |
| @@ -1237,6 +1238,11 @@ static int intel_fbc_check_plane(struct intel_atomic_state *state, · 1175 unmodified lines | ||
| 1237 | 1238 | return 0; |
| 1238 | 1239 | } |
| 1239 | 1240 | |
| 1241 | + if (intel_display_needs_wa_16023588340(i915)) { | |
| 1242 | + plane_state->no_fbc_reason = "Wa_16023588340"; | |
| 1243 | + return 0; | |
| 1244 | + } | |
| 1245 | + | |
| 1240 | 1246 | /* WaFbcTurnOffFbcWhenHyperVisorIsUsed:skl,bxt */ |
| 1241 | 1247 | if (i915_vtd_active(i915) && (IS_SKYLAKE(i915) || IS_BROXTON(i915))) { |
| 1242 | 1248 | plane_state->no_fbc_reason = "VT-d enabled"; |
| @@ -12,32 +12,15 @@ subdir-ccflags-$(CONFIG_DRM_XE_WERROR) += -Werror · 11 unmodified lines | ||
| 12 | 12 | subdir-ccflags-y += -I$(obj) -I$(src) |
| 13 | 13 | |
| 14 | 14 | # generated sources |
| 15 | −hostprogs := xe_gen_wa_oob | |
| 16 | 15 | |
| 16 | +hostprogs := xe_gen_wa_oob | |
| 17 | 17 | generated_oob := $(obj)/generated/xe_wa_oob.c $(obj)/generated/xe_wa_oob.h |
| 18 | − | |
| 19 | 18 | quiet_cmd_wa_oob = GEN $(notdir $(generated_oob)) |
| 20 | 19 | cmd_wa_oob = mkdir -p $(@D); $^ $(generated_oob) |
| 21 | − | |
| 22 | 20 | $(obj)/generated/%_wa_oob.c $(obj)/generated/%_wa_oob.h: $(obj)/xe_gen_wa_oob \ |
| 23 | 21 | $(src)/xe_wa_oob.rules |
| 24 | 22 | $(call cmd,wa_oob) |
| 25 | 23 | |
| 26 | −uses_generated_oob := \ | |
| 27 | − $(obj)/xe_ggtt.o \ | |
| 28 | − $(obj)/xe_gsc.o \ | |
| 29 | − $(obj)/xe_gt.o \ | |
| 30 | − $(obj)/xe_guc.o \ | |
| 31 | − $(obj)/xe_guc_ads.o \ | |
| 32 | − $(obj)/xe_guc_pc.o \ | |
| 33 | − $(obj)/xe_migrate.o \ | |
| 34 | − $(obj)/xe_ring_ops.o \ | |
| 35 | − $(obj)/xe_vm.o \ | |
| 36 | − $(obj)/xe_wa.o \ | |
| 37 | − $(obj)/xe_ttm_stolen_mgr.o | |
| 38 | − | |
| 39 | −$(uses_generated_oob): $(generated_oob) | |
| 40 | − | |
| 41 | 24 | # Please keep these build lists sorted! |
| 42 | 25 | |
| 43 | 26 | # core driver code |
| @@ -192,6 +175,7 @@ xe-$(CONFIG_DRM_XE_DISPLAY) += \ · 148 unmodified lines | ||
| 192 | 175 | display/xe_display.o \ |
| 193 | 176 | display/xe_display_misc.o \ |
| 194 | 177 | display/xe_display_rps.o \ |
| 178 | + display/xe_display_wa.o \ | |
| 195 | 179 | display/xe_dsb_buffer.o \ |
| 196 | 180 | display/xe_fb_pin.o \ |
| 197 | 181 | display/xe_hdcp_gsc.o \ |
| @@ -320,3 +304,6 @@ quiet_cmd_hdrtest = HDRTEST $(patsubst %.hdrtest,%.h,$@) · 122 unmodified lines | ||
| 320 | 304 | |
| 321 | 305 | $(obj)/%.hdrtest: $(src)/%.h FORCE |
| 322 | 306 | $(call if_changed_dep,hdrtest) |
| 307 | + | |
| 308 | +uses_generated_oob := $(addprefix $(obj)/, $(xe-y)) | |
| 309 | +$(uses_generated_oob): $(obj)/generated/xe_wa_oob.h | |
| @@ -10,6 +10,9 @@ · 9 unmodified lines | ||
| 10 | 10 | #include "xe_bo.h" |
| 11 | 11 | #include "xe_gt.h" |
| 12 | 12 | #include "xe_ttm_stolen_mgr.h" |
| 13 | +#include "xe_wa.h" | |
| 14 | + | |
| 15 | +#include <generated/xe_wa_oob.h> | |
| 13 | 16 | |
| 14 | 17 | struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, |
| 15 | 18 | struct drm_fb_helper_surface_size *sizes) |
| @@ -37,7 +40,7 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, · 21 unmodified lines | ||
| 37 | 40 | size = PAGE_ALIGN(size); |
| 38 | 41 | obj = ERR_PTR(-ENODEV); |
| 39 | 42 | |
| 40 | − if (!IS_DGFX(xe)) { | |
| 43 | + if (!IS_DGFX(xe) && !XE_WA(xe_root_mmio_gt(xe), 22019338487_display)) { | |
| 41 | 44 | obj = xe_bo_create_pin_map(xe, xe_device_get_root_tile(xe), |
| 42 | 45 | NULL, size, |
| 43 | 46 | ttm_bo_type_kernel, XE_BO_FLAG_SCANOUT | |
| @@ -48,6 +51,7 @@ struct intel_framebuffer *intel_fbdev_fb_alloc(struct drm_fb_helper *helper, · 4 unmodified lines | ||
| 48 | 51 | else |
| 49 | 52 | drm_info(&xe->drm, "Allocated fbdev into stolen failed: %li\n", PTR_ERR(obj)); |
| 50 | 53 | } |
| 54 | + | |
| 51 | 55 | if (IS_ERR(obj)) { |
| 52 | 56 | obj = xe_bo_create_pin_map(xe, xe_device_get_root_tile(xe), NULL, size, |
| 53 | 57 | ttm_bo_type_kernel, XE_BO_FLAG_SCANOUT | |
| @@ -0,0 +1,16 @@ | ||
| 1 | +// SPDX-License-Identifier: MIT | |
| 2 | +/* | |
| 3 | + * Copyright © 2024 Intel Corporation | |
| 4 | + */ | |
| 5 | + | |
| 6 | +#include "intel_display_wa.h" | |
| 7 | + | |
| 8 | +#include "xe_device.h" | |
| 9 | +#include "xe_wa.h" | |
| 10 | + | |
| 11 | +#include <generated/xe_wa_oob.h> | |
| 12 | + | |
| 13 | +bool intel_display_needs_wa_16023588340(struct drm_i915_private *i915) | |
| 14 | +{ | |
| 15 | + return XE_WA(xe_root_mmio_gt(i915), 16023588340); | |
| 16 | +} | |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | ||
| 7 | 7 | #include "intel_display_types.h" |
| 8 | 8 | #include "intel_dsb_buffer.h" |
| 9 | 9 | #include "xe_bo.h" |
| 10 | +#include "xe_device.h" | |
| 11 | +#include "xe_device_types.h" | |
| 10 | 12 | #include "xe_gt.h" |
| 11 | 13 | |
| 12 | 14 | u32 intel_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf) |
| @@ -16,7 +18,10 @@ u32 intel_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf) · 3 unmodified lines | ||
| 16 | 18 | |
| 17 | 19 | void intel_dsb_buffer_write(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val) |
| 18 | 20 | { |
| 21 | + struct xe_device *xe = dsb_buf->vma->bo->tile->xe; | |
| 22 | + | |
| 19 | 23 | iosys_map_wr(&dsb_buf->vma->bo->vmap, idx * 4, u32, val); |
| 24 | + xe_device_l2_flush(xe); | |
| 20 | 25 | } |
| 21 | 26 | |
| 22 | 27 | u32 intel_dsb_buffer_read(struct intel_dsb_buffer *dsb_buf, u32 idx) |
| @@ -26,9 +31,12 @@ u32 intel_dsb_buffer_read(struct intel_dsb_buffer *dsb_buf, u32 idx) · 3 unmodified lines | ||
| 26 | 31 | |
| 27 | 32 | void intel_dsb_buffer_memset(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val, size_t size) |
| 28 | 33 | { |
| 34 | + struct xe_device *xe = dsb_buf->vma->bo->tile->xe; | |
| 35 | + | |
| 29 | 36 | WARN_ON(idx > (dsb_buf->buf_size - size) / sizeof(*dsb_buf->cmd_buf)); |
| 30 | 37 | |
| 31 | 38 | iosys_map_memset(&dsb_buf->vma->bo->vmap, idx * 4, val, size); |
| 39 | + xe_device_l2_flush(xe); | |
| 32 | 40 | } |
| 33 | 41 | |
| 34 | 42 | bool intel_dsb_buffer_create(struct intel_crtc *crtc, struct intel_dsb_buffer *dsb_buf, size_t size) |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include "intel_fb.h" |
| 11 | 11 | #include "intel_fb_pin.h" |
| 12 | 12 | #include "xe_bo.h" |
| 13 | +#include "xe_device.h" | |
| 13 | 14 | #include "xe_ggtt.h" |
| 14 | 15 | #include "xe_gt.h" |
| 15 | 16 | #include "xe_pm.h" |
| @@ -304,6 +305,8 @@ static struct i915_vma *__xe_pin_fb_vma(const struct intel_framebuffer *fb, · 288 unmodified lines | ||
| 304 | 305 | if (ret) |
| 305 | 306 | goto err_unpin; |
| 306 | 307 | |
| 308 | + /* Ensure DPT writes are flushed */ | |
| 309 | + xe_device_l2_flush(xe); | |
| 307 | 310 | return vma; |
| 308 | 311 | |
| 309 | 312 | err_unpin: |
| @@ -18,6 +18,9 @@ · 17 unmodified lines | ||
| 18 | 18 | #include "intel_frontbuffer.h" |
| 19 | 19 | #include "intel_plane_initial.h" |
| 20 | 20 | #include "xe_bo.h" |
| 21 | +#include "xe_wa.h" | |
| 22 | + | |
| 23 | +#include <generated/xe_wa_oob.h> | |
| 21 | 24 | |
| 22 | 25 | static bool |
| 23 | 26 | intel_reuse_initial_plane_obj(struct intel_crtc *this, |
| @@ -104,6 +107,9 @@ initial_plane_bo(struct xe_device *xe, · 80 unmodified lines | ||
| 104 | 107 | phys_base = base; |
| 105 | 108 | flags |= XE_BO_FLAG_STOLEN; |
| 106 | 109 | |
| 110 | + if (XE_WA(xe_root_mmio_gt(xe), 22019338487_display)) | |
| 111 | + return NULL; | |
| 112 | + | |
| 107 | 113 | /* |
| 108 | 114 | * If the FB is too big, just don't use it since fbdev is not very |
| 109 | 115 | * important and we should probably use that space with FBC or other |
| @@ -80,6 +80,9 @@ · 79 unmodified lines | ||
| 80 | 80 | #define LE_CACHEABILITY_MASK REG_GENMASK(1, 0) |
| 81 | 81 | #define LE_CACHEABILITY(value) REG_FIELD_PREP(LE_CACHEABILITY_MASK, value) |
| 82 | 82 | |
| 83 | +#define XE2_GAMREQSTRM_CTRL XE_REG(0x4194) | |
| 84 | +#define CG_DIS_CNTLBUS REG_BIT(6) | |
| 85 | + | |
| 83 | 86 | #define CCS_AUX_INV XE_REG(0x4208) |
| 84 | 87 | |
| 85 | 88 | #define VD0_AUX_INV XE_REG(0x4218) |
| @@ -88,6 +91,8 @@ · 2 unmodified lines | ||
| 88 | 91 | #define VE1_AUX_INV XE_REG(0x42b8) |
| 89 | 92 | #define AUX_INV REG_BIT(0) |
| 90 | 93 | |
| 94 | +#define XE2_LMEM_CFG XE_REG(0x48b0) | |
| 95 | + | |
| 91 | 96 | #define XEHP_TILE_ADDR_RANGE(_idx) XE_REG_MCR(0x4900 + (_idx) * 4) |
| 92 | 97 | #define XEHP_FLAT_CCS_BASE_ADDR XE_REG_MCR(0x4910) |
| 93 | 98 | #define XEHP_FLAT_CCS_PTR REG_GENMASK(31, 8) |
| @@ -103,6 +108,7 @@ · 9 unmodified lines | ||
| 103 | 108 | |
| 104 | 109 | #define FF_MODE XE_REG_MCR(0x6210) |
| 105 | 110 | #define DIS_TE_AUTOSTRIP REG_BIT(31) |
| 111 | +#define VS_HIT_MAX_VALUE_MASK REG_GENMASK(25, 20) | |
| 106 | 112 | #define DIS_MESH_PARTIAL_AUTOSTRIP REG_BIT(16) |
| 107 | 113 | #define DIS_MESH_AUTOSTRIP REG_BIT(15) |
| 108 | 114 | |
| @@ -372,6 +378,11 @@ · 263 unmodified lines | ||
| 372 | 378 | |
| 373 | 379 | #define XEHPC_L3CLOS_MASK(i) XE_REG_MCR(0xb194 + (i) * 8) |
| 374 | 380 | |
| 381 | +#define XE2_GLOBAL_INVAL XE_REG(0xb404) | |
| 382 | + | |
| 383 | +#define SCRATCH1LPFC XE_REG(0xb474) | |
| 384 | +#define EN_L3_RW_CCS_CACHE_FLUSH REG_BIT(0) | |
| 385 | + | |
| 375 | 386 | #define XE2LPM_L3SQCREG5 XE_REG_MCR(0xb658) |
| 376 | 387 | |
| 377 | 388 | #define XE2_TDF_CTRL XE_REG(0xb418) |
| @@ -395,6 +406,10 @@ · 17 unmodified lines | ||
| 395 | 406 | #define INVALIDATION_BROADCAST_MODE_DIS REG_BIT(12) |
| 396 | 407 | #define GLOBAL_INVALIDATION_MODE REG_BIT(2) |
| 397 | 408 | |
| 409 | +#define LMEM_CFG XE_REG(0xcf58) | |
| 410 | +#define LMEM_EN REG_BIT(31) | |
| 411 | +#define LMTT_DIR_PTR REG_GENMASK(30, 0) /* in multiples of 64KB */ | |
| 412 | + | |
| 398 | 413 | #define HALF_SLICE_CHICKEN5 XE_REG_MCR(0xe188, XE_REG_OPTION_MASKED) |
| 399 | 414 | #define DISABLE_SAMPLE_G_PERFORMANCE REG_BIT(0) |
| 400 | 415 | |
| @@ -15,8 +15,6 @@ · 14 unmodified lines | ||
| 15 | 15 | #define GU_MISC_IRQ_OFFSET 0x444f0 |
| 16 | 16 | #define GU_MISC_GSE REG_BIT(27) |
| 17 | 17 | |
| 18 | −#define SOFTWARE_FLAGS_SPR33 XE_REG(0x4f084) | |
| 19 | − | |
| 20 | 18 | #define GU_CNTL_PROTECTED XE_REG(0x10100C) |
| 21 | 19 | #define DRIVERINT_FLR_DIS REG_BIT(31) |
| 22 | 20 | |
| @@ -24,11 +22,14 @@ · 1 unmodified line | ||
| 24 | 22 | #define LMEM_INIT REG_BIT(7) |
| 25 | 23 | #define DRIVERFLR REG_BIT(31) |
| 26 | 24 | |
| 25 | +#define XEHP_CLOCK_GATE_DIS XE_REG(0x101014) | |
| 26 | +#define SGSI_SIDECLK_DIS REG_BIT(17) | |
| 27 | + | |
| 27 | 28 | #define GU_DEBUG XE_REG(0x101018) |
| 28 | 29 | #define DRIVERFLR_STATUS REG_BIT(31) |
| 29 | 30 | |
| 30 | −#define XEHP_CLOCK_GATE_DIS XE_REG(0x101014) | |
| 31 | −#define SGSI_SIDECLK_DIS REG_BIT(17) | |
| 31 | +#define VIRTUAL_CTRL_REG XE_REG(0x10108c) | |
| 32 | +#define GUEST_GTT_UPDATE_EN REG_BIT(8) | |
| 32 | 33 | |
| 33 | 34 | #define XEHP_MTCFG_ADDR XE_REG(0x101800) |
| 34 | 35 | #define TILE_COUNT REG_GENMASK(15, 8) |
| @@ -66,6 +67,9 @@ · 31 unmodified lines | ||
| 66 | 67 | #define DISPLAY_IRQ REG_BIT(16) |
| 67 | 68 | #define GT_DW_IRQ(x) REG_BIT(x) |
| 68 | 69 | |
| 70 | +#define VF_CAP_REG XE_REG(0x1901f8, XE_REG_OPTION_VF) | |
| 71 | +#define VF_CAP REG_BIT(0) | |
| 72 | + | |
| 69 | 73 | #define PVC_RP_STATE_CAP XE_REG(0x281014) |
| 70 | 74 | |
| 71 | 75 | #endif |
| @@ -1,23 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: MIT */ | |
| 2 | −/* | |
| 3 | − * Copyright © 2023 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#ifndef _REGS_XE_SRIOV_REGS_H_ | |
| 7 | −#define _REGS_XE_SRIOV_REGS_H_ | |
| 8 | − | |
| 9 | −#include "regs/xe_reg_defs.h" | |
| 10 | − | |
| 11 | −#define XE2_LMEM_CFG XE_REG(0x48b0) | |
| 12 | − | |
| 13 | −#define LMEM_CFG XE_REG(0xcf58) | |
| 14 | −#define LMEM_EN REG_BIT(31) | |
| 15 | −#define LMTT_DIR_PTR REG_GENMASK(30, 0) /* in multiples of 64KB */ | |
| 16 | − | |
| 17 | −#define VIRTUAL_CTRL_REG XE_REG(0x10108c) | |
| 18 | −#define GUEST_GTT_UPDATE_EN REG_BIT(8) | |
| 19 | − | |
| 20 | −#define VF_CAP_REG XE_REG(0x1901f8, XE_REG_OPTION_VF) | |
| 21 | −#define VF_CAP REG_BIT(0) | |
| 22 | − | |
| 23 | −#endif | |
| @@ -2,11 +2,7 @@ · 1 unmodified line | ||
| 2 | 2 | |
| 3 | 3 | # "live" kunit tests |
| 4 | 4 | obj-$(CONFIG_DRM_XE_KUNIT_TEST) += xe_live_test.o |
| 5 | −xe_live_test-y = xe_live_test_mod.o \ | |
| 6 | − xe_bo_test.o \ | |
| 7 | − xe_dma_buf_test.o \ | |
| 8 | − xe_migrate_test.o \ | |
| 9 | − xe_mocs_test.o | |
| 5 | +xe_live_test-y = xe_live_test_mod.o | |
| 10 | 6 | |
| 11 | 7 | # Normal kunit tests |
| 12 | 8 | obj-$(CONFIG_DRM_XE_KUNIT_TEST) += xe_test.o |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <kunit/test.h> |
| 7 | 7 | #include <kunit/visibility.h> |
| 8 | 8 | |
| 9 | −#include "tests/xe_bo_test.h" | |
| 9 | +#include "tests/xe_kunit_helpers.h" | |
| 10 | 10 | #include "tests/xe_pci_test.h" |
| 11 | 11 | #include "tests/xe_test.h" |
| 12 | 12 | |
| @@ -154,12 +154,18 @@ out_unlock: · 141 unmodified lines | ||
| 154 | 154 | |
| 155 | 155 | static int ccs_test_run_device(struct xe_device *xe) |
| 156 | 156 | { |
| 157 | − struct kunit *test = xe_cur_kunit(); | |
| 157 | + struct kunit *test = kunit_get_current_test(); | |
| 158 | 158 | struct xe_tile *tile; |
| 159 | 159 | int id; |
| 160 | 160 | |
| 161 | 161 | if (!xe_device_has_flat_ccs(xe)) { |
| 162 | − kunit_info(test, "Skipping non-flat-ccs device.\n"); | |
| 162 | + kunit_skip(test, "non-flat-ccs device\n"); | |
| 163 | + return 0; | |
| 164 | + } | |
| 165 | + | |
| 166 | + /* For xe2+ dgfx, we don't handle ccs metadata */ | |
| 167 | + if (GRAPHICS_VER(xe) >= 20 && IS_DGFX(xe)) { | |
| 168 | + kunit_skip(test, "xe2+ dgfx device\n"); | |
| 163 | 169 | return 0; |
| 164 | 170 | } |
| 165 | 171 | |
| @@ -177,11 +183,12 @@ static int ccs_test_run_device(struct xe_device *xe) · 11 unmodified lines | ||
| 177 | 183 | return 0; |
| 178 | 184 | } |
| 179 | 185 | |
| 180 | −void xe_ccs_migrate_kunit(struct kunit *test) | |
| 186 | +static void xe_ccs_migrate_kunit(struct kunit *test) | |
| 181 | 187 | { |
| 182 | − xe_call_for_each_device(ccs_test_run_device); | |
| 188 | + struct xe_device *xe = test->priv; | |
| 189 | + | |
| 190 | + ccs_test_run_device(xe); | |
| 183 | 191 | } |
| 184 | −EXPORT_SYMBOL_IF_KUNIT(xe_ccs_migrate_kunit); | |
| 185 | 192 | |
| 186 | 193 | static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struct kunit *test) |
| 187 | 194 | { |
| @@ -325,13 +332,12 @@ cleanup_bo: · 137 unmodified lines | ||
| 325 | 332 | |
| 326 | 333 | static int evict_test_run_device(struct xe_device *xe) |
| 327 | 334 | { |
| 328 | − struct kunit *test = xe_cur_kunit(); | |
| 335 | + struct kunit *test = kunit_get_current_test(); | |
| 329 | 336 | struct xe_tile *tile; |
| 330 | 337 | int id; |
| 331 | 338 | |
| 332 | 339 | if (!IS_DGFX(xe)) { |
| 333 | − kunit_info(test, "Skipping non-discrete device %s.\n", | |
| 334 | − dev_name(xe->drm.dev)); | |
| 340 | + kunit_skip(test, "non-discrete device\n"); | |
| 335 | 341 | return 0; |
| 336 | 342 | } |
| 337 | 343 | |
| @@ -345,8 +351,23 @@ static int evict_test_run_device(struct xe_device *xe) · 7 unmodified lines | ||
| 345 | 351 | return 0; |
| 346 | 352 | } |
| 347 | 353 | |
| 348 | −void xe_bo_evict_kunit(struct kunit *test) | |
| 354 | +static void xe_bo_evict_kunit(struct kunit *test) | |
| 349 | 355 | { |
| 350 | − xe_call_for_each_device(evict_test_run_device); | |
| 356 | + struct xe_device *xe = test->priv; | |
| 357 | + | |
| 358 | + evict_test_run_device(xe); | |
| 351 | 359 | } |
| 352 | −EXPORT_SYMBOL_IF_KUNIT(xe_bo_evict_kunit); | |
| 360 | + | |
| 361 | +static struct kunit_case xe_bo_tests[] = { | |
| 362 | + KUNIT_CASE_PARAM(xe_ccs_migrate_kunit, xe_pci_live_device_gen_param), | |
| 363 | + KUNIT_CASE_PARAM(xe_bo_evict_kunit, xe_pci_live_device_gen_param), | |
| 364 | + {} | |
| 365 | +}; | |
| 366 | + | |
| 367 | +VISIBLE_IF_KUNIT | |
| 368 | +struct kunit_suite xe_bo_test_suite = { | |
| 369 | + .name = "xe_bo", | |
| 370 | + .test_cases = xe_bo_tests, | |
| 371 | + .init = xe_kunit_helper_xe_device_live_test_init, | |
| 372 | +}; | |
| 373 | +EXPORT_SYMBOL_IF_KUNIT(xe_bo_test_suite); | |
| @@ -1,21 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0 | |
| 2 | −/* | |
| 3 | − * Copyright © 2022 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#include "xe_bo_test.h" | |
| 7 | − | |
| 8 | −#include <kunit/test.h> | |
| 9 | − | |
| 10 | −static struct kunit_case xe_bo_tests[] = { | |
| 11 | − KUNIT_CASE(xe_ccs_migrate_kunit), | |
| 12 | − KUNIT_CASE(xe_bo_evict_kunit), | |
| 13 | − {} | |
| 14 | −}; | |
| 15 | − | |
| 16 | −static struct kunit_suite xe_bo_test_suite = { | |
| 17 | − .name = "xe_bo", | |
| 18 | − .test_cases = xe_bo_tests, | |
| 19 | −}; | |
| 20 | − | |
| 21 | −kunit_test_suite(xe_bo_test_suite); | |
| @@ -1,14 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 AND MIT */ | |
| 2 | −/* | |
| 3 | − * Copyright © 2023 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#ifndef _XE_BO_TEST_H_ | |
| 7 | −#define _XE_BO_TEST_H_ | |
| 8 | − | |
| 9 | −struct kunit; | |
| 10 | − | |
| 11 | −void xe_ccs_migrate_kunit(struct kunit *test); | |
| 12 | −void xe_bo_evict_kunit(struct kunit *test); | |
| 13 | − | |
| 14 | −#endif | |
| @@ -8,7 +8,7 @@ · 7 unmodified lines | ||
| 8 | 8 | #include <kunit/test.h> |
| 9 | 9 | #include <kunit/visibility.h> |
| 10 | 10 | |
| 11 | −#include "tests/xe_dma_buf_test.h" | |
| 11 | +#include "tests/xe_kunit_helpers.h" | |
| 12 | 12 | #include "tests/xe_pci_test.h" |
| 13 | 13 | |
| 14 | 14 | #include "xe_pci.h" |
| @@ -107,7 +107,7 @@ static void check_residency(struct kunit *test, struct xe_bo *exported, · 92 unmodified lines | ||
| 107 | 107 | |
| 108 | 108 | static void xe_test_dmabuf_import_same_driver(struct xe_device *xe) |
| 109 | 109 | { |
| 110 | − struct kunit *test = xe_cur_kunit(); | |
| 110 | + struct kunit *test = kunit_get_current_test(); | |
| 111 | 111 | struct dma_buf_test_params *params = to_dma_buf_test_params(test->priv); |
| 112 | 112 | struct drm_gem_object *import; |
| 113 | 113 | struct dma_buf *dmabuf; |
| @@ -258,7 +258,7 @@ static const struct dma_buf_test_params test_params[] = { · 144 unmodified lines | ||
| 258 | 258 | static int dma_buf_run_device(struct xe_device *xe) |
| 259 | 259 | { |
| 260 | 260 | const struct dma_buf_test_params *params; |
| 261 | − struct kunit *test = xe_cur_kunit(); | |
| 261 | + struct kunit *test = kunit_get_current_test(); | |
| 262 | 262 | |
| 263 | 263 | xe_pm_runtime_get(xe); |
| 264 | 264 | for (params = test_params; params->mem_mask; ++params) { |
| @@ -274,8 +274,22 @@ static int dma_buf_run_device(struct xe_device *xe) · 9 unmodified lines | ||
| 274 | 274 | return 0; |
| 275 | 275 | } |
| 276 | 276 | |
| 277 | −void xe_dma_buf_kunit(struct kunit *test) | |
| 277 | +static void xe_dma_buf_kunit(struct kunit *test) | |
| 278 | 278 | { |
| 279 | − xe_call_for_each_device(dma_buf_run_device); | |
| 279 | + struct xe_device *xe = test->priv; | |
| 280 | + | |
| 281 | + dma_buf_run_device(xe); | |
| 280 | 282 | } |
| 281 | −EXPORT_SYMBOL_IF_KUNIT(xe_dma_buf_kunit); | |
| 283 | + | |
| 284 | +static struct kunit_case xe_dma_buf_tests[] = { | |
| 285 | + KUNIT_CASE_PARAM(xe_dma_buf_kunit, xe_pci_live_device_gen_param), | |
| 286 | + {} | |
| 287 | +}; | |
| 288 | + | |
| 289 | +VISIBLE_IF_KUNIT | |
| 290 | +struct kunit_suite xe_dma_buf_test_suite = { | |
| 291 | + .name = "xe_dma_buf", | |
| 292 | + .test_cases = xe_dma_buf_tests, | |
| 293 | + .init = xe_kunit_helper_xe_device_live_test_init, | |
| 294 | +}; | |
| 295 | +EXPORT_SYMBOL_IF_KUNIT(xe_dma_buf_test_suite); | |
| @@ -1,20 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0 | |
| 2 | −/* | |
| 3 | − * Copyright © 2022 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#include "xe_dma_buf_test.h" | |
| 7 | − | |
| 8 | −#include <kunit/test.h> | |
| 9 | − | |
| 10 | −static struct kunit_case xe_dma_buf_tests[] = { | |
| 11 | − KUNIT_CASE(xe_dma_buf_kunit), | |
| 12 | − {} | |
| 13 | −}; | |
| 14 | − | |
| 15 | −static struct kunit_suite xe_dma_buf_test_suite = { | |
| 16 | − .name = "xe_dma_buf", | |
| 17 | − .test_cases = xe_dma_buf_tests, | |
| 18 | −}; | |
| 19 | − | |
| 20 | −kunit_test_suite(xe_dma_buf_test_suite); | |
| @@ -1,13 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 AND MIT */ | |
| 2 | −/* | |
| 3 | − * Copyright © 2023 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#ifndef _XE_DMA_BUF_TEST_H_ | |
| 7 | −#define _XE_DMA_BUF_TEST_H_ | |
| 8 | − | |
| 9 | −struct kunit; | |
| 10 | − | |
| 11 | −void xe_dma_buf_kunit(struct kunit *test); | |
| 12 | − | |
| 13 | −#endif | |
| @@ -12,7 +12,9 @@ · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | #include "tests/xe_kunit_helpers.h" |
| 14 | 14 | #include "tests/xe_pci_test.h" |
| 15 | +#include "xe_device.h" | |
| 15 | 16 | #include "xe_device_types.h" |
| 17 | +#include "xe_pm.h" | |
| 16 | 18 | |
| 17 | 19 | /** |
| 18 | 20 | * xe_kunit_helper_alloc_xe_device - Allocate a &xe_device for a KUnit test. |
| @@ -88,3 +90,40 @@ int xe_kunit_helper_xe_device_test_init(struct kunit *test) · 69 unmodified lines | ||
| 88 | 90 | return 0; |
| 89 | 91 | } |
| 90 | 92 | EXPORT_SYMBOL_IF_KUNIT(xe_kunit_helper_xe_device_test_init); |
| 93 | + | |
| 94 | +KUNIT_DEFINE_ACTION_WRAPPER(put_xe_pm_runtime, xe_pm_runtime_put, struct xe_device *); | |
| 95 | + | |
| 96 | +/** | |
| 97 | + * xe_kunit_helper_xe_device_live_test_init - Prepare a &xe_device for | |
| 98 | + * use in a live KUnit test. | |
| 99 | + * @test: the &kunit where live &xe_device will be used | |
| 100 | + * | |
| 101 | + * This function expects pointer to the &xe_device in the &test.param_value, | |
| 102 | + * like it is prepared by the &xe_pci_live_device_gen_param and stores that | |
| 103 | + * pointer as &kunit.priv to allow the test code to access it. | |
| 104 | + * | |
| 105 | + * This function makes sure that device is not wedged and then resumes it | |
| 106 | + * to avoid waking up the device inside the test. It uses deferred cleanup | |
| 107 | + * action to release a runtime_pm reference. | |
| 108 | + * | |
| 109 | + * This function can be used as custom implementation of &kunit_suite.init. | |
| 110 | + * | |
| 111 | + * This function uses KUNIT_ASSERT to detect any failures. | |
| 112 | + * | |
| 113 | + * Return: Always 0. | |
| 114 | + */ | |
| 115 | +int xe_kunit_helper_xe_device_live_test_init(struct kunit *test) | |
| 116 | +{ | |
| 117 | + struct xe_device *xe = xe_device_const_cast(test->param_value); | |
| 118 | + | |
| 119 | + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe); | |
| 120 | + kunit_info(test, "running on %s device\n", xe->info.platform_name); | |
| 121 | + | |
| 122 | + KUNIT_ASSERT_FALSE(test, xe_device_wedged(xe)); | |
| 123 | + xe_pm_runtime_get(xe); | |
| 124 | + KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test, put_xe_pm_runtime, xe)); | |
| 125 | + | |
| 126 | + test->priv = xe; | |
| 127 | + return 0; | |
| 128 | +} | |
| 129 | +EXPORT_SYMBOL_IF_KUNIT(xe_kunit_helper_xe_device_live_test_init); | |
| @@ -14,4 +14,6 @@ struct xe_device *xe_kunit_helper_alloc_xe_device(struct kunit *test, · 13 unmodified lines | ||
| 14 | 14 | struct device *dev); |
| 15 | 15 | int xe_kunit_helper_xe_device_test_init(struct kunit *test); |
| 16 | 16 | |
| 17 | +int xe_kunit_helper_xe_device_live_test_init(struct kunit *test); | |
| 18 | + | |
| 17 | 19 | #endif |
| @@ -3,6 +3,17 @@ · 2 unmodified lines | ||
| 3 | 3 | * Copyright © 2023 Intel Corporation |
| 4 | 4 | */ |
| 5 | 5 | #include <linux/module.h> |
| 6 | +#include <kunit/test.h> | |
| 7 | + | |
| 8 | +extern struct kunit_suite xe_bo_test_suite; | |
| 9 | +extern struct kunit_suite xe_dma_buf_test_suite; | |
| 10 | +extern struct kunit_suite xe_migrate_test_suite; | |
| 11 | +extern struct kunit_suite xe_mocs_test_suite; | |
| 12 | + | |
| 13 | +kunit_test_suite(xe_bo_test_suite); | |
| 14 | +kunit_test_suite(xe_dma_buf_test_suite); | |
| 15 | +kunit_test_suite(xe_migrate_test_suite); | |
| 16 | +kunit_test_suite(xe_mocs_test_suite); | |
| 6 | 17 | |
| 7 | 18 | MODULE_AUTHOR("Intel Corporation"); |
| 8 | 19 | MODULE_LICENSE("GPL"); |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <kunit/test.h> |
| 7 | 7 | #include <kunit/visibility.h> |
| 8 | 8 | |
| 9 | −#include "tests/xe_migrate_test.h" | |
| 9 | +#include "tests/xe_kunit_helpers.h" | |
| 10 | 10 | #include "tests/xe_pci_test.h" |
| 11 | 11 | |
| 12 | 12 | #include "xe_pci.h" |
| @@ -334,7 +334,7 @@ vunmap: · 321 unmodified lines | ||
| 334 | 334 | |
| 335 | 335 | static int migrate_test_run_device(struct xe_device *xe) |
| 336 | 336 | { |
| 337 | − struct kunit *test = xe_cur_kunit(); | |
| 337 | + struct kunit *test = kunit_get_current_test(); | |
| 338 | 338 | struct xe_tile *tile; |
| 339 | 339 | int id; |
| 340 | 340 | |
| @@ -354,8 +354,422 @@ static int migrate_test_run_device(struct xe_device *xe) · 13 unmodified lines | ||
| 354 | 354 | return 0; |
| 355 | 355 | } |
| 356 | 356 | |
| 357 | −void xe_migrate_sanity_kunit(struct kunit *test) | |
| 357 | +static void xe_migrate_sanity_kunit(struct kunit *test) | |
| 358 | 358 | { |
| 359 | − xe_call_for_each_device(migrate_test_run_device); | |
| 359 | + struct xe_device *xe = test->priv; | |
| 360 | + | |
| 361 | + migrate_test_run_device(xe); | |
| 362 | +} | |
| 363 | + | |
| 364 | +static struct dma_fence *blt_copy(struct xe_tile *tile, | |
| 365 | + struct xe_bo *src_bo, struct xe_bo *dst_bo, | |
| 366 | + bool copy_only_ccs, const char *str, struct kunit *test) | |
| 367 | +{ | |
| 368 | + struct xe_gt *gt = tile->primary_gt; | |
| 369 | + struct xe_migrate *m = tile->migrate; | |
| 370 | + struct xe_device *xe = gt_to_xe(gt); | |
| 371 | + struct dma_fence *fence = NULL; | |
| 372 | + u64 size = src_bo->size; | |
| 373 | + struct xe_res_cursor src_it, dst_it; | |
| 374 | + struct ttm_resource *src = src_bo->ttm.resource, *dst = dst_bo->ttm.resource; | |
| 375 | + u64 src_L0_ofs, dst_L0_ofs; | |
| 376 | + u32 src_L0_pt, dst_L0_pt; | |
| 377 | + u64 src_L0, dst_L0; | |
| 378 | + int err; | |
| 379 | + bool src_is_vram = mem_type_is_vram(src->mem_type); | |
| 380 | + bool dst_is_vram = mem_type_is_vram(dst->mem_type); | |
| 381 | + | |
| 382 | + if (!src_is_vram) | |
| 383 | + xe_res_first_sg(xe_bo_sg(src_bo), 0, size, &src_it); | |
| 384 | + else | |
| 385 | + xe_res_first(src, 0, size, &src_it); | |
| 386 | + | |
| 387 | + if (!dst_is_vram) | |
| 388 | + xe_res_first_sg(xe_bo_sg(dst_bo), 0, size, &dst_it); | |
| 389 | + else | |
| 390 | + xe_res_first(dst, 0, size, &dst_it); | |
| 391 | + | |
| 392 | + while (size) { | |
| 393 | + u32 batch_size = 2; /* arb_clear() + MI_BATCH_BUFFER_END */ | |
| 394 | + struct xe_sched_job *job; | |
| 395 | + struct xe_bb *bb; | |
| 396 | + u32 flush_flags = 0; | |
| 397 | + u32 update_idx; | |
| 398 | + u32 avail_pts = max_mem_transfer_per_pass(xe) / LEVEL0_PAGE_TABLE_ENCODE_SIZE; | |
| 399 | + u32 pte_flags; | |
| 400 | + | |
| 401 | + src_L0 = xe_migrate_res_sizes(m, &src_it); | |
| 402 | + dst_L0 = xe_migrate_res_sizes(m, &dst_it); | |
| 403 | + | |
| 404 | + src_L0 = min(src_L0, dst_L0); | |
| 405 | + | |
| 406 | + pte_flags = src_is_vram ? (PTE_UPDATE_FLAG_IS_VRAM | | |
| 407 | + PTE_UPDATE_FLAG_IS_COMP_PTE) : 0; | |
| 408 | + batch_size += pte_update_size(m, pte_flags, src, &src_it, &src_L0, | |
| 409 | + &src_L0_ofs, &src_L0_pt, 0, 0, | |
| 410 | + avail_pts); | |
| 411 | + | |
| 412 | + pte_flags = dst_is_vram ? (PTE_UPDATE_FLAG_IS_VRAM | | |
| 413 | + PTE_UPDATE_FLAG_IS_COMP_PTE) : 0; | |
| 414 | + batch_size += pte_update_size(m, pte_flags, dst, &dst_it, &src_L0, | |
| 415 | + &dst_L0_ofs, &dst_L0_pt, 0, | |
| 416 | + avail_pts, avail_pts); | |
| 417 | + | |
| 418 | + /* Add copy commands size here */ | |
| 419 | + batch_size += ((copy_only_ccs) ? 0 : EMIT_COPY_DW) + | |
| 420 | + ((xe_device_has_flat_ccs(xe) && copy_only_ccs) ? EMIT_COPY_CCS_DW : 0); | |
| 421 | + | |
| 422 | + bb = xe_bb_new(gt, batch_size, xe->info.has_usm); | |
| 423 | + if (IS_ERR(bb)) { | |
| 424 | + err = PTR_ERR(bb); | |
| 425 | + goto err_sync; | |
| 426 | + } | |
| 427 | + | |
| 428 | + if (src_is_vram) | |
| 429 | + xe_res_next(&src_it, src_L0); | |
| 430 | + else | |
| 431 | + emit_pte(m, bb, src_L0_pt, src_is_vram, false, | |
| 432 | + &src_it, src_L0, src); | |
| 433 | + | |
| 434 | + if (dst_is_vram) | |
| 435 | + xe_res_next(&dst_it, src_L0); | |
| 436 | + else | |
| 437 | + emit_pte(m, bb, dst_L0_pt, dst_is_vram, false, | |
| 438 | + &dst_it, src_L0, dst); | |
| 439 | + | |
| 440 | + bb->cs[bb->len++] = MI_BATCH_BUFFER_END; | |
| 441 | + update_idx = bb->len; | |
| 442 | + if (!copy_only_ccs) | |
| 443 | + emit_copy(gt, bb, src_L0_ofs, dst_L0_ofs, src_L0, XE_PAGE_SIZE); | |
| 444 | + | |
| 445 | + if (copy_only_ccs) | |
| 446 | + flush_flags = xe_migrate_ccs_copy(m, bb, src_L0_ofs, | |
| 447 | + src_is_vram, dst_L0_ofs, | |
| 448 | + dst_is_vram, src_L0, dst_L0_ofs, | |
| 449 | + copy_only_ccs); | |
| 450 | + | |
| 451 | + job = xe_bb_create_migration_job(m->q, bb, | |
| 452 | + xe_migrate_batch_base(m, xe->info.has_usm), | |
| 453 | + update_idx); | |
| 454 | + if (IS_ERR(job)) { | |
| 455 | + err = PTR_ERR(job); | |
| 456 | + goto err; | |
| 457 | + } | |
| 458 | + | |
| 459 | + xe_sched_job_add_migrate_flush(job, flush_flags); | |
| 460 | + | |
| 461 | + mutex_lock(&m->job_mutex); | |
| 462 | + xe_sched_job_arm(job); | |
| 463 | + dma_fence_put(fence); | |
| 464 | + fence = dma_fence_get(&job->drm.s_fence->finished); | |
| 465 | + xe_sched_job_push(job); | |
| 466 | + | |
| 467 | + dma_fence_put(m->fence); | |
| 468 | + m->fence = dma_fence_get(fence); | |
| 469 | + | |
| 470 | + mutex_unlock(&m->job_mutex); | |
| 471 | + | |
| 472 | + xe_bb_free(bb, fence); | |
| 473 | + size -= src_L0; | |
| 474 | + continue; | |
| 475 | + | |
| 476 | +err: | |
| 477 | + xe_bb_free(bb, NULL); | |
| 478 | + | |
| 479 | +err_sync: | |
| 480 | + if (fence) { | |
| 481 | + dma_fence_wait(fence, false); | |
| 482 | + dma_fence_put(fence); | |
| 483 | + } | |
| 484 | + return ERR_PTR(err); | |
| 485 | + } | |
| 486 | + | |
| 487 | + return fence; | |
| 488 | +} | |
| 489 | + | |
| 490 | +static void test_migrate(struct xe_device *xe, struct xe_tile *tile, | |
| 491 | + struct xe_bo *sys_bo, struct xe_bo *vram_bo, struct xe_bo *ccs_bo, | |
| 492 | + struct kunit *test) | |
| 493 | +{ | |
| 494 | + struct dma_fence *fence; | |
| 495 | + u64 expected, retval; | |
| 496 | + long timeout; | |
| 497 | + long ret; | |
| 498 | + | |
| 499 | + expected = 0xd0d0d0d0d0d0d0d0; | |
| 500 | + xe_map_memset(xe, &sys_bo->vmap, 0, 0xd0, sys_bo->size); | |
| 501 | + | |
| 502 | + fence = blt_copy(tile, sys_bo, vram_bo, false, "Blit copy from sysmem to vram", test); | |
| 503 | + if (!sanity_fence_failed(xe, fence, "Blit copy from sysmem to vram", test)) { | |
| 504 | + retval = xe_map_rd(xe, &vram_bo->vmap, 0, u64); | |
| 505 | + if (retval == expected) | |
| 506 | + KUNIT_FAIL(test, "Sanity check failed: VRAM must have compressed value\n"); | |
| 507 | + } | |
| 508 | + dma_fence_put(fence); | |
| 509 | + | |
| 510 | + kunit_info(test, "Evict vram buffer object\n"); | |
| 511 | + ret = xe_bo_evict(vram_bo, true); | |
| 512 | + if (ret) { | |
| 513 | + KUNIT_FAIL(test, "Failed to evict bo.\n"); | |
| 514 | + return; | |
| 515 | + } | |
| 516 | + | |
| 517 | + ret = xe_bo_vmap(vram_bo); | |
| 518 | + if (ret) { | |
| 519 | + KUNIT_FAIL(test, "Failed to vmap vram bo: %li\n", ret); | |
| 520 | + return; | |
| 521 | + } | |
| 522 | + | |
| 523 | + retval = xe_map_rd(xe, &vram_bo->vmap, 0, u64); | |
| 524 | + check(retval, expected, "Clear evicted vram data first value", test); | |
| 525 | + retval = xe_map_rd(xe, &vram_bo->vmap, vram_bo->size - 8, u64); | |
| 526 | + check(retval, expected, "Clear evicted vram data last value", test); | |
| 527 | + | |
| 528 | + fence = blt_copy(tile, vram_bo, ccs_bo, | |
| 529 | + true, "Blit surf copy from vram to sysmem", test); | |
| 530 | + if (!sanity_fence_failed(xe, fence, "Clear ccs buffer data", test)) { | |
| 531 | + retval = xe_map_rd(xe, &ccs_bo->vmap, 0, u64); | |
| 532 | + check(retval, 0, "Clear ccs data first value", test); | |
| 533 | + | |
| 534 | + retval = xe_map_rd(xe, &ccs_bo->vmap, ccs_bo->size - 8, u64); | |
| 535 | + check(retval, 0, "Clear ccs data last value", test); | |
| 536 | + } | |
| 537 | + dma_fence_put(fence); | |
| 538 | + | |
| 539 | + kunit_info(test, "Restore vram buffer object\n"); | |
| 540 | + ret = xe_bo_validate(vram_bo, NULL, false); | |
| 541 | + if (ret) { | |
| 542 | + KUNIT_FAIL(test, "Failed to validate vram bo for: %li\n", ret); | |
| 543 | + return; | |
| 544 | + } | |
| 545 | + | |
| 546 | + /* Sync all migration blits */ | |
| 547 | + timeout = dma_resv_wait_timeout(vram_bo->ttm.base.resv, | |
| 548 | + DMA_RESV_USAGE_KERNEL, | |
| 549 | + true, | |
| 550 | + 5 * HZ); | |
| 551 | + if (timeout <= 0) { | |
| 552 | + KUNIT_FAIL(test, "Failed to sync bo eviction.\n"); | |
| 553 | + return; | |
| 554 | + } | |
| 555 | + | |
| 556 | + ret = xe_bo_vmap(vram_bo); | |
| 557 | + if (ret) { | |
| 558 | + KUNIT_FAIL(test, "Failed to vmap vram bo: %li\n", ret); | |
| 559 | + return; | |
| 560 | + } | |
| 561 | + | |
| 562 | + retval = xe_map_rd(xe, &vram_bo->vmap, 0, u64); | |
| 563 | + check(retval, expected, "Restored value must be equal to initial value", test); | |
| 564 | + retval = xe_map_rd(xe, &vram_bo->vmap, vram_bo->size - 8, u64); | |
| 565 | + check(retval, expected, "Restored value must be equal to initial value", test); | |
| 566 | + | |
| 567 | + fence = blt_copy(tile, vram_bo, ccs_bo, | |
| 568 | + true, "Blit surf copy from vram to sysmem", test); | |
| 569 | + if (!sanity_fence_failed(xe, fence, "Clear ccs buffer data", test)) { | |
| 570 | + retval = xe_map_rd(xe, &ccs_bo->vmap, 0, u64); | |
| 571 | + check(retval, 0, "Clear ccs data first value", test); | |
| 572 | + retval = xe_map_rd(xe, &ccs_bo->vmap, ccs_bo->size - 8, u64); | |
| 573 | + check(retval, 0, "Clear ccs data last value", test); | |
| 574 | + } | |
| 575 | + dma_fence_put(fence); | |
| 576 | +} | |
| 577 | + | |
| 578 | +static void test_clear(struct xe_device *xe, struct xe_tile *tile, | |
| 579 | + struct xe_bo *sys_bo, struct xe_bo *vram_bo, struct kunit *test) | |
| 580 | +{ | |
| 581 | + struct dma_fence *fence; | |
| 582 | + u64 expected, retval; | |
| 583 | + | |
| 584 | + expected = 0xd0d0d0d0d0d0d0d0; | |
| 585 | + xe_map_memset(xe, &sys_bo->vmap, 0, 0xd0, sys_bo->size); | |
| 586 | + | |
| 587 | + fence = blt_copy(tile, sys_bo, vram_bo, false, "Blit copy from sysmem to vram", test); | |
| 588 | + if (!sanity_fence_failed(xe, fence, "Blit copy from sysmem to vram", test)) { | |
| 589 | + retval = xe_map_rd(xe, &vram_bo->vmap, 0, u64); | |
| 590 | + if (retval == expected) | |
| 591 | + KUNIT_FAIL(test, "Sanity check failed: VRAM must have compressed value\n"); | |
| 592 | + } | |
| 593 | + dma_fence_put(fence); | |
| 594 | + | |
| 595 | + fence = blt_copy(tile, vram_bo, sys_bo, false, "Blit copy from vram to sysmem", test); | |
| 596 | + if (!sanity_fence_failed(xe, fence, "Blit copy from vram to sysmem", test)) { | |
| 597 | + retval = xe_map_rd(xe, &sys_bo->vmap, 0, u64); | |
| 598 | + check(retval, expected, "Decompressed value must be equal to initial value", test); | |
| 599 | + retval = xe_map_rd(xe, &sys_bo->vmap, sys_bo->size - 8, u64); | |
| 600 | + check(retval, expected, "Decompressed value must be equal to initial value", test); | |
| 601 | + } | |
| 602 | + dma_fence_put(fence); | |
| 603 | + | |
| 604 | + kunit_info(test, "Clear vram buffer object\n"); | |
| 605 | + expected = 0x0000000000000000; | |
| 606 | + fence = xe_migrate_clear(tile->migrate, vram_bo, vram_bo->ttm.resource); | |
| 607 | + if (sanity_fence_failed(xe, fence, "Clear vram_bo", test)) | |
| 608 | + return; | |
| 609 | + dma_fence_put(fence); | |
| 610 | + | |
| 611 | + fence = blt_copy(tile, vram_bo, sys_bo, | |
| 612 | + false, "Blit copy from vram to sysmem", test); | |
| 613 | + if (!sanity_fence_failed(xe, fence, "Clear main buffer data", test)) { | |
| 614 | + retval = xe_map_rd(xe, &sys_bo->vmap, 0, u64); | |
| 615 | + check(retval, expected, "Clear main buffer first value", test); | |
| 616 | + retval = xe_map_rd(xe, &sys_bo->vmap, sys_bo->size - 8, u64); | |
| 617 | + check(retval, expected, "Clear main buffer last value", test); | |
| 618 | + } | |
| 619 | + dma_fence_put(fence); | |
| 620 | + | |
| 621 | + fence = blt_copy(tile, vram_bo, sys_bo, | |
| 622 | + true, "Blit surf copy from vram to sysmem", test); | |
| 623 | + if (!sanity_fence_failed(xe, fence, "Clear ccs buffer data", test)) { | |
| 624 | + retval = xe_map_rd(xe, &sys_bo->vmap, 0, u64); | |
| 625 | + check(retval, expected, "Clear ccs data first value", test); | |
| 626 | + retval = xe_map_rd(xe, &sys_bo->vmap, sys_bo->size - 8, u64); | |
| 627 | + check(retval, expected, "Clear ccs data last value", test); | |
| 628 | + } | |
| 629 | + dma_fence_put(fence); | |
| 630 | +} | |
| 631 | + | |
| 632 | +static void validate_ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile, | |
| 633 | + struct kunit *test) | |
| 634 | +{ | |
| 635 | + struct xe_bo *sys_bo, *vram_bo = NULL, *ccs_bo = NULL; | |
| 636 | + unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile); | |
| 637 | + long ret; | |
| 638 | + | |
| 639 | + sys_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M, | |
| 640 | + DRM_XE_GEM_CPU_CACHING_WC, ttm_bo_type_device, | |
| 641 | + XE_BO_FLAG_SYSTEM | XE_BO_FLAG_NEEDS_CPU_ACCESS); | |
| 642 | + | |
| 643 | + if (IS_ERR(sys_bo)) { | |
| 644 | + KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n", | |
| 645 | + PTR_ERR(sys_bo)); | |
| 646 | + return; | |
| 647 | + } | |
| 648 | + | |
| 649 | + xe_bo_lock(sys_bo, false); | |
| 650 | + ret = xe_bo_validate(sys_bo, NULL, false); | |
| 651 | + if (ret) { | |
| 652 | + KUNIT_FAIL(test, "Failed to validate system bo for: %li\n", ret); | |
| 653 | + goto free_sysbo; | |
| 654 | + } | |
| 655 | + | |
| 656 | + ret = xe_bo_vmap(sys_bo); | |
| 657 | + if (ret) { | |
| 658 | + KUNIT_FAIL(test, "Failed to vmap system bo: %li\n", ret); | |
| 659 | + goto free_sysbo; | |
| 660 | + } | |
| 661 | + xe_bo_unlock(sys_bo); | |
| 662 | + | |
| 663 | + ccs_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M, DRM_XE_GEM_CPU_CACHING_WC, | |
| 664 | + ttm_bo_type_device, bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS); | |
| 665 | + | |
| 666 | + if (IS_ERR(ccs_bo)) { | |
| 667 | + KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n", | |
| 668 | + PTR_ERR(ccs_bo)); | |
| 669 | + return; | |
| 670 | + } | |
| 671 | + | |
| 672 | + xe_bo_lock(ccs_bo, false); | |
| 673 | + ret = xe_bo_validate(ccs_bo, NULL, false); | |
| 674 | + if (ret) { | |
| 675 | + KUNIT_FAIL(test, "Failed to validate system bo for: %li\n", ret); | |
| 676 | + goto free_ccsbo; | |
| 677 | + } | |
| 678 | + | |
| 679 | + ret = xe_bo_vmap(ccs_bo); | |
| 680 | + if (ret) { | |
| 681 | + KUNIT_FAIL(test, "Failed to vmap system bo: %li\n", ret); | |
| 682 | + goto free_ccsbo; | |
| 683 | + } | |
| 684 | + xe_bo_unlock(ccs_bo); | |
| 685 | + | |
| 686 | + vram_bo = xe_bo_create_user(xe, NULL, NULL, SZ_4M, DRM_XE_GEM_CPU_CACHING_WC, | |
| 687 | + ttm_bo_type_device, bo_flags | XE_BO_FLAG_NEEDS_CPU_ACCESS); | |
| 688 | + if (IS_ERR(vram_bo)) { | |
| 689 | + KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n", | |
| 690 | + PTR_ERR(vram_bo)); | |
| 691 | + return; | |
| 692 | + } | |
| 693 | + | |
| 694 | + xe_bo_lock(vram_bo, false); | |
| 695 | + ret = xe_bo_validate(vram_bo, NULL, false); | |
| 696 | + if (ret) { | |
| 697 | + KUNIT_FAIL(test, "Failed to validate vram bo for: %li\n", ret); | |
| 698 | + goto free_vrambo; | |
| 699 | + } | |
| 700 | + | |
| 701 | + ret = xe_bo_vmap(vram_bo); | |
| 702 | + if (ret) { | |
| 703 | + KUNIT_FAIL(test, "Failed to vmap vram bo: %li\n", ret); | |
| 704 | + goto free_vrambo; | |
| 705 | + } | |
| 706 | + | |
| 707 | + test_clear(xe, tile, sys_bo, vram_bo, test); | |
| 708 | + test_migrate(xe, tile, sys_bo, vram_bo, ccs_bo, test); | |
| 709 | + xe_bo_unlock(vram_bo); | |
| 710 | + | |
| 711 | + xe_bo_lock(vram_bo, false); | |
| 712 | + xe_bo_vunmap(vram_bo); | |
| 713 | + xe_bo_unlock(vram_bo); | |
| 714 | + | |
| 715 | + xe_bo_lock(ccs_bo, false); | |
| 716 | + xe_bo_vunmap(ccs_bo); | |
| 717 | + xe_bo_unlock(ccs_bo); | |
| 718 | + | |
| 719 | + xe_bo_lock(sys_bo, false); | |
| 720 | + xe_bo_vunmap(sys_bo); | |
| 721 | + xe_bo_unlock(sys_bo); | |
| 722 | +free_vrambo: | |
| 723 | + xe_bo_put(vram_bo); | |
| 724 | +free_ccsbo: | |
| 725 | + xe_bo_put(ccs_bo); | |
| 726 | +free_sysbo: | |
| 727 | + xe_bo_put(sys_bo); | |
| 728 | +} | |
| 729 | + | |
| 730 | +static int validate_ccs_test_run_device(struct xe_device *xe) | |
| 731 | +{ | |
| 732 | + struct kunit *test = kunit_get_current_test(); | |
| 733 | + struct xe_tile *tile; | |
| 734 | + int id; | |
| 735 | + | |
| 736 | + if (!xe_device_has_flat_ccs(xe)) { | |
| 737 | + kunit_skip(test, "non-flat-ccs device\n"); | |
| 738 | + return 0; | |
| 739 | + } | |
| 740 | + | |
| 741 | + if (!(GRAPHICS_VER(xe) >= 20 && IS_DGFX(xe))) { | |
| 742 | + kunit_skip(test, "non-xe2 discrete device\n"); | |
| 743 | + return 0; | |
| 744 | + } | |
| 745 | + | |
| 746 | + xe_pm_runtime_get(xe); | |
| 747 | + | |
| 748 | + for_each_tile(tile, xe, id) | |
| 749 | + validate_ccs_test_run_tile(xe, tile, test); | |
| 750 | + | |
| 751 | + xe_pm_runtime_put(xe); | |
| 752 | + | |
| 753 | + return 0; | |
| 360 | 754 | } |
| 361 | −EXPORT_SYMBOL_IF_KUNIT(xe_migrate_sanity_kunit); | |
| 755 | + | |
| 756 | +static void xe_validate_ccs_kunit(struct kunit *test) | |
| 757 | +{ | |
| 758 | + struct xe_device *xe = test->priv; | |
| 759 | + | |
| 760 | + validate_ccs_test_run_device(xe); | |
| 761 | +} | |
| 762 | + | |
| 763 | +static struct kunit_case xe_migrate_tests[] = { | |
| 764 | + KUNIT_CASE_PARAM(xe_migrate_sanity_kunit, xe_pci_live_device_gen_param), | |
| 765 | + KUNIT_CASE_PARAM(xe_validate_ccs_kunit, xe_pci_live_device_gen_param), | |
| 766 | + {} | |
| 767 | +}; | |
| 768 | + | |
| 769 | +VISIBLE_IF_KUNIT | |
| 770 | +struct kunit_suite xe_migrate_test_suite = { | |
| 771 | + .name = "xe_migrate", | |
| 772 | + .test_cases = xe_migrate_tests, | |
| 773 | + .init = xe_kunit_helper_xe_device_live_test_init, | |
| 774 | +}; | |
| 775 | +EXPORT_SYMBOL_IF_KUNIT(xe_migrate_test_suite); | |
| @@ -1,20 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0 | |
| 2 | −/* | |
| 3 | − * Copyright © 2022 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#include "xe_migrate_test.h" | |
| 7 | − | |
| 8 | −#include <kunit/test.h> | |
| 9 | − | |
| 10 | −static struct kunit_case xe_migrate_tests[] = { | |
| 11 | − KUNIT_CASE(xe_migrate_sanity_kunit), | |
| 12 | − {} | |
| 13 | −}; | |
| 14 | − | |
| 15 | −static struct kunit_suite xe_migrate_test_suite = { | |
| 16 | − .name = "xe_migrate", | |
| 17 | − .test_cases = xe_migrate_tests, | |
| 18 | −}; | |
| 19 | − | |
| 20 | −kunit_test_suite(xe_migrate_test_suite); | |
| @@ -1,13 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 AND MIT */ | |
| 2 | −/* | |
| 3 | − * Copyright © 2023 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#ifndef _XE_MIGRATE_TEST_H_ | |
| 7 | −#define _XE_MIGRATE_TEST_H_ | |
| 8 | − | |
| 9 | −struct kunit; | |
| 10 | − | |
| 11 | −void xe_migrate_sanity_kunit(struct kunit *test); | |
| 12 | − | |
| 13 | −#endif | |
| @@ -6,7 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include <kunit/test.h> |
| 7 | 7 | #include <kunit/visibility.h> |
| 8 | 8 | |
| 9 | −#include "tests/xe_mocs_test.h" | |
| 9 | +#include "tests/xe_kunit_helpers.h" | |
| 10 | 10 | #include "tests/xe_pci_test.h" |
| 11 | 11 | #include "tests/xe_test.h" |
| 12 | 12 | |
| @@ -23,7 +23,7 @@ struct live_mocs { · 10 unmodified lines | ||
| 23 | 23 | static int live_mocs_init(struct live_mocs *arg, struct xe_gt *gt) |
| 24 | 24 | { |
| 25 | 25 | unsigned int flags; |
| 26 | − struct kunit *test = xe_cur_kunit(); | |
| 26 | + struct kunit *test = kunit_get_current_test(); | |
| 27 | 27 | |
| 28 | 28 | memset(arg, 0, sizeof(*arg)); |
| 29 | 29 | |
| @@ -41,7 +41,7 @@ static int live_mocs_init(struct live_mocs *arg, struct xe_gt *gt) · 11 unmodified lines | ||
| 41 | 41 | static void read_l3cc_table(struct xe_gt *gt, |
| 42 | 42 | const struct xe_mocs_info *info) |
| 43 | 43 | { |
| 44 | − struct kunit *test = xe_cur_kunit(); | |
| 44 | + struct kunit *test = kunit_get_current_test(); | |
| 45 | 45 | u32 l3cc, l3cc_expected; |
| 46 | 46 | unsigned int i; |
| 47 | 47 | u32 reg_val; |
| @@ -78,7 +78,7 @@ static void read_l3cc_table(struct xe_gt *gt, · 30 unmodified lines | ||
| 78 | 78 | static void read_mocs_table(struct xe_gt *gt, |
| 79 | 79 | const struct xe_mocs_info *info) |
| 80 | 80 | { |
| 81 | − struct kunit *test = xe_cur_kunit(); | |
| 81 | + struct kunit *test = kunit_get_current_test(); | |
| 82 | 82 | u32 mocs, mocs_expected; |
| 83 | 83 | unsigned int i; |
| 84 | 84 | u32 reg_val; |
| @@ -134,11 +134,15 @@ static int mocs_kernel_test_run_device(struct xe_device *xe) · 49 unmodified lines | ||
| 134 | 134 | return 0; |
| 135 | 135 | } |
| 136 | 136 | |
| 137 | −void xe_live_mocs_kernel_kunit(struct kunit *test) | |
| 137 | +static void xe_live_mocs_kernel_kunit(struct kunit *test) | |
| 138 | 138 | { |
| 139 | − xe_call_for_each_device(mocs_kernel_test_run_device); | |
| 139 | + struct xe_device *xe = test->priv; | |
| 140 | + | |
| 141 | + if (IS_SRIOV_VF(xe)) | |
| 142 | + kunit_skip(test, "this test is N/A for VF"); | |
| 143 | + | |
| 144 | + mocs_kernel_test_run_device(xe); | |
| 140 | 145 | } |
| 141 | −EXPORT_SYMBOL_IF_KUNIT(xe_live_mocs_kernel_kunit); | |
| 142 | 146 | |
| 143 | 147 | static int mocs_reset_test_run_device(struct xe_device *xe) |
| 144 | 148 | { |
| @@ -148,7 +152,7 @@ static int mocs_reset_test_run_device(struct xe_device *xe) · 3 unmodified lines | ||
| 148 | 152 | struct xe_gt *gt; |
| 149 | 153 | unsigned int flags; |
| 150 | 154 | int id; |
| 151 | − struct kunit *test = xe_cur_kunit(); | |
| 155 | + struct kunit *test = kunit_get_current_test(); | |
| 152 | 156 | |
| 153 | 157 | xe_pm_runtime_get(xe); |
| 154 | 158 | |
| @@ -175,8 +179,26 @@ static int mocs_reset_test_run_device(struct xe_device *xe) · 20 unmodified lines | ||
| 175 | 179 | return 0; |
| 176 | 180 | } |
| 177 | 181 | |
| 178 | −void xe_live_mocs_reset_kunit(struct kunit *test) | |
| 182 | +static void xe_live_mocs_reset_kunit(struct kunit *test) | |
| 179 | 183 | { |
| 180 | − xe_call_for_each_device(mocs_reset_test_run_device); | |
| 184 | + struct xe_device *xe = test->priv; | |
| 185 | + | |
| 186 | + if (IS_SRIOV_VF(xe)) | |
| 187 | + kunit_skip(test, "this test is N/A for VF"); | |
| 188 | + | |
| 189 | + mocs_reset_test_run_device(xe); | |
| 181 | 190 | } |
| 182 | −EXPORT_SYMBOL_IF_KUNIT(xe_live_mocs_reset_kunit); | |
| 191 | + | |
| 192 | +static struct kunit_case xe_mocs_tests[] = { | |
| 193 | + KUNIT_CASE_PARAM(xe_live_mocs_kernel_kunit, xe_pci_live_device_gen_param), | |
| 194 | + KUNIT_CASE_PARAM(xe_live_mocs_reset_kunit, xe_pci_live_device_gen_param), | |
| 195 | + {} | |
| 196 | +}; | |
| 197 | + | |
| 198 | +VISIBLE_IF_KUNIT | |
| 199 | +struct kunit_suite xe_mocs_test_suite = { | |
| 200 | + .name = "xe_mocs", | |
| 201 | + .test_cases = xe_mocs_tests, | |
| 202 | + .init = xe_kunit_helper_xe_device_live_test_init, | |
| 203 | +}; | |
| 204 | +EXPORT_SYMBOL_IF_KUNIT(xe_mocs_test_suite); | |
| @@ -1,21 +0,0 @@ | ||
| 1 | −// SPDX-License-Identifier: GPL-2.0 | |
| 2 | −/* | |
| 3 | − * Copyright © 2022 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#include "xe_mocs_test.h" | |
| 7 | − | |
| 8 | −#include <kunit/test.h> | |
| 9 | − | |
| 10 | −static struct kunit_case xe_mocs_tests[] = { | |
| 11 | − KUNIT_CASE(xe_live_mocs_kernel_kunit), | |
| 12 | − KUNIT_CASE(xe_live_mocs_reset_kunit), | |
| 13 | − {} | |
| 14 | −}; | |
| 15 | − | |
| 16 | −static struct kunit_suite xe_mocs_test_suite = { | |
| 17 | − .name = "xe_mocs", | |
| 18 | − .test_cases = xe_mocs_tests, | |
| 19 | −}; | |
| 20 | − | |
| 21 | −kunit_test_suite(xe_mocs_test_suite); | |
| @@ -1,14 +0,0 @@ | ||
| 1 | −/* SPDX-License-Identifier: GPL-2.0 AND MIT */ | |
| 2 | −/* | |
| 3 | − * Copyright © 2023 Intel Corporation | |
| 4 | − */ | |
| 5 | − | |
| 6 | −#ifndef _XE_MOCS_TEST_H_ | |
| 7 | −#define _XE_MOCS_TEST_H_ | |
| 8 | − | |
| 9 | −struct kunit; | |
| 10 | − | |
| 11 | −void xe_live_mocs_kernel_kunit(struct kunit *test); | |
| 12 | −void xe_live_mocs_reset_kunit(struct kunit *test); | |
| 13 | − | |
| 14 | −#endif | |
| @@ -167,3 +167,33 @@ done: · 166 unmodified lines | ||
| 167 | 167 | return 0; |
| 168 | 168 | } |
| 169 | 169 | EXPORT_SYMBOL_IF_KUNIT(xe_pci_fake_device_init); |
| 170 | + | |
| 171 | +/** | |
| 172 | + * xe_pci_live_device_gen_param - Helper to iterate Xe devices as KUnit parameters | |
| 173 | + * @prev: the previously returned value, or NULL for the first iteration | |
| 174 | + * @desc: the buffer for a parameter name | |
| 175 | + * | |
| 176 | + * Iterates over the available Xe devices on the system. Uses the device name | |
| 177 | + * as the parameter name. | |
| 178 | + * | |
| 179 | + * To be used only as a parameter generator function in &KUNIT_CASE_PARAM. | |
| 180 | + * | |
| 181 | + * Return: pointer to the next &struct xe_device ready to be used as a parameter | |
| 182 | + * or NULL if there are no more Xe devices on the system. | |
| 183 | + */ | |
| 184 | +const void *xe_pci_live_device_gen_param(const void *prev, char *desc) | |
| 185 | +{ | |
| 186 | + const struct xe_device *xe = prev; | |
| 187 | + struct device *dev = xe ? xe->drm.dev : NULL; | |
| 188 | + struct device *next; | |
| 189 | + | |
| 190 | + next = driver_find_next_device(&xe_pci_driver.driver, dev); | |
| 191 | + if (dev) | |
| 192 | + put_device(dev); | |
| 193 | + if (!next) | |
| 194 | + return NULL; | |
| 195 | + | |
| 196 | + snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%s", dev_name(next)); | |
| 197 | + return pdev_to_xe_device(to_pci_dev(next)); | |
| 198 | +} | |
| 199 | +EXPORT_SYMBOL_IF_KUNIT(xe_pci_live_device_gen_param); | |
| @@ -16,7 +16,7 @@ · 15 unmodified lines | ||
| 16 | 16 | |
| 17 | 17 | static void check_graphics_ip(const struct xe_graphics_desc *graphics) |
| 18 | 18 | { |
| 19 | − struct kunit *test = xe_cur_kunit(); | |
| 19 | + struct kunit *test = kunit_get_current_test(); | |
| 20 | 20 | u64 mask = graphics->hw_engine_mask; |
| 21 | 21 | |
| 22 | 22 | /* RCS, CCS, and BCS engines are allowed on the graphics IP */ |
| @@ -30,7 +30,7 @@ static void check_graphics_ip(const struct xe_graphics_desc *graphics) · 7 unmodified lines | ||
| 30 | 30 | |
| 31 | 31 | static void check_media_ip(const struct xe_media_desc *media) |
| 32 | 32 | { |
| 33 | − struct kunit *test = xe_cur_kunit(); | |
| 33 | + struct kunit *test = kunit_get_current_test(); | |
| 34 | 34 | u64 mask = media->hw_engine_mask; |
| 35 | 35 | |
| 36 | 36 | /* VCS, VECS and GSCCS engines are allowed on the media IP */ |
| @@ -35,4 +35,6 @@ struct xe_pci_fake_data { · 34 unmodified lines | ||
| 35 | 35 | |
| 36 | 36 | int xe_pci_fake_device_init(struct xe_device *xe); |
| 37 | 37 | |
| 38 | +const void *xe_pci_live_device_gen_param(const void *prev, char *desc); | |
| 39 | + | |
| 38 | 40 | #endif |
| @@ -31,16 +31,23 @@ · 30 unmodified lines | ||
| 31 | 31 | #undef XE_REG_MCR |
| 32 | 32 | #define XE_REG_MCR(...) XE_REG(__VA_ARGS__, .mcr = 1) |
| 33 | 33 | |
| 34 | −struct rtp_test_case { | |
| 34 | +struct rtp_to_sr_test_case { | |
| 35 | 35 | const char *name; |
| 36 | 36 | struct xe_reg expected_reg; |
| 37 | 37 | u32 expected_set_bits; |
| 38 | 38 | u32 expected_clr_bits; |
| 39 | − unsigned long expected_count; | |
| 39 | + unsigned long expected_count_sr_entries; | |
| 40 | 40 | unsigned int expected_sr_errors; |
| 41 | + unsigned long expected_active; | |
| 41 | 42 | const struct xe_rtp_entry_sr *entries; |
| 42 | 43 | }; |
| 43 | 44 | |
| 45 | +struct rtp_test_case { | |
| 46 | + const char *name; | |
| 47 | + unsigned long expected_active; | |
| 48 | + const struct xe_rtp_entry *entries; | |
| 49 | +}; | |
| 50 | + | |
| 44 | 51 | static bool match_yes(const struct xe_gt *gt, const struct xe_hw_engine *hwe) |
| 45 | 52 | { |
| 46 | 53 | return true; |
| @@ -51,13 +58,14 @@ static bool match_no(const struct xe_gt *gt, const struct xe_hw_engine *hwe) · 4 unmodified lines | ||
| 51 | 58 | return false; |
| 52 | 59 | } |
| 53 | 60 | |
| 54 | −static const struct rtp_test_case cases[] = { | |
| 61 | +static const struct rtp_to_sr_test_case rtp_to_sr_cases[] = { | |
| 55 | 62 | { |
| 56 | 63 | .name = "coalesce-same-reg", |
| 57 | 64 | .expected_reg = REGULAR_REG1, |
| 58 | 65 | .expected_set_bits = REG_BIT(0) | REG_BIT(1), |
| 59 | 66 | .expected_clr_bits = REG_BIT(0) | REG_BIT(1), |
| 60 | − .expected_count = 1, | |
| 67 | + .expected_active = BIT(0) | BIT(1), | |
| 68 | + .expected_count_sr_entries = 1, | |
| 61 | 69 | /* Different bits on the same register: create a single entry */ |
| 62 | 70 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 63 | 71 | { XE_RTP_NAME("basic-1"), |
| @@ -76,7 +84,8 @@ static const struct rtp_test_case cases[] = { · 12 unmodified lines | ||
| 76 | 84 | .expected_reg = REGULAR_REG1, |
| 77 | 85 | .expected_set_bits = REG_BIT(0), |
| 78 | 86 | .expected_clr_bits = REG_BIT(0), |
| 79 | − .expected_count = 1, | |
| 87 | + .expected_active = BIT(0), | |
| 88 | + .expected_count_sr_entries = 1, | |
| 80 | 89 | /* Don't coalesce second entry since rules don't match */ |
| 81 | 90 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 82 | 91 | { XE_RTP_NAME("basic-1"), |
| @@ -95,7 +104,8 @@ static const struct rtp_test_case cases[] = { · 12 unmodified lines | ||
| 95 | 104 | .expected_reg = REGULAR_REG1, |
| 96 | 105 | .expected_set_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2), |
| 97 | 106 | .expected_clr_bits = REG_BIT(0) | REG_BIT(1) | REG_BIT(2), |
| 98 | − .expected_count = 1, | |
| 107 | + .expected_active = BIT(0) | BIT(1) | BIT(2), | |
| 108 | + .expected_count_sr_entries = 1, | |
| 99 | 109 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 100 | 110 | { XE_RTP_NAME("first"), |
| 101 | 111 | XE_RTP_RULES(FUNC(match_yes), OR, FUNC(match_no)), |
| @@ -121,7 +131,7 @@ static const struct rtp_test_case cases[] = { · 19 unmodified lines | ||
| 121 | 131 | { |
| 122 | 132 | .name = "match-or-xfail", |
| 123 | 133 | .expected_reg = REGULAR_REG1, |
| 124 | − .expected_count = 0, | |
| 134 | + .expected_count_sr_entries = 0, | |
| 125 | 135 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 126 | 136 | { XE_RTP_NAME("leading-or"), |
| 127 | 137 | XE_RTP_RULES(OR, FUNC(match_yes)), |
| @@ -148,7 +158,8 @@ static const struct rtp_test_case cases[] = { · 20 unmodified lines | ||
| 148 | 158 | .expected_reg = REGULAR_REG1, |
| 149 | 159 | .expected_set_bits = REG_BIT(0), |
| 150 | 160 | .expected_clr_bits = REG_BIT(0), |
| 151 | − .expected_count = 1, | |
| 161 | + .expected_active = BIT(0), | |
| 162 | + .expected_count_sr_entries = 1, | |
| 152 | 163 | /* Don't coalesce second entry due to one of the rules */ |
| 153 | 164 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 154 | 165 | { XE_RTP_NAME("basic-1"), |
| @@ -167,7 +178,8 @@ static const struct rtp_test_case cases[] = { · 12 unmodified lines | ||
| 167 | 178 | .expected_reg = REGULAR_REG1, |
| 168 | 179 | .expected_set_bits = REG_BIT(0), |
| 169 | 180 | .expected_clr_bits = REG_BIT(0), |
| 170 | − .expected_count = 2, | |
| 181 | + .expected_active = BIT(0) | BIT(1), | |
| 182 | + .expected_count_sr_entries = 2, | |
| 171 | 183 | /* Same bits on different registers are not coalesced */ |
| 172 | 184 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 173 | 185 | { XE_RTP_NAME("basic-1"), |
| @@ -186,7 +198,8 @@ static const struct rtp_test_case cases[] = { · 12 unmodified lines | ||
| 186 | 198 | .expected_reg = REGULAR_REG1, |
| 187 | 199 | .expected_set_bits = REG_BIT(0), |
| 188 | 200 | .expected_clr_bits = REG_BIT(1) | REG_BIT(0), |
| 189 | − .expected_count = 1, | |
| 201 | + .expected_active = BIT(0) | BIT(1), | |
| 202 | + .expected_count_sr_entries = 1, | |
| 190 | 203 | /* Check clr vs set actions on different bits */ |
| 191 | 204 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 192 | 205 | { XE_RTP_NAME("basic-1"), |
| @@ -207,7 +220,8 @@ static const struct rtp_test_case cases[] = { · 14 unmodified lines | ||
| 207 | 220 | .expected_reg = REGULAR_REG1, |
| 208 | 221 | .expected_set_bits = TEMP_FIELD, |
| 209 | 222 | .expected_clr_bits = TEMP_MASK, |
| 210 | − .expected_count = 1, | |
| 223 | + .expected_active = BIT(0), | |
| 224 | + .expected_count_sr_entries = 1, | |
| 211 | 225 | /* Check FIELD_SET works */ |
| 212 | 226 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 213 | 227 | { XE_RTP_NAME("basic-1"), |
| @@ -225,7 +239,8 @@ static const struct rtp_test_case cases[] = { · 11 unmodified lines | ||
| 225 | 239 | .expected_reg = REGULAR_REG1, |
| 226 | 240 | .expected_set_bits = REG_BIT(0), |
| 227 | 241 | .expected_clr_bits = REG_BIT(0), |
| 228 | − .expected_count = 1, | |
| 242 | + .expected_active = BIT(0) | BIT(1), | |
| 243 | + .expected_count_sr_entries = 1, | |
| 229 | 244 | .expected_sr_errors = 1, |
| 230 | 245 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 231 | 246 | { XE_RTP_NAME("basic-1"), |
| @@ -245,7 +260,8 @@ static const struct rtp_test_case cases[] = { · 13 unmodified lines | ||
| 245 | 260 | .expected_reg = REGULAR_REG1, |
| 246 | 261 | .expected_set_bits = REG_BIT(0), |
| 247 | 262 | .expected_clr_bits = REG_BIT(0), |
| 248 | − .expected_count = 1, | |
| 263 | + .expected_active = BIT(0) | BIT(1), | |
| 264 | + .expected_count_sr_entries = 1, | |
| 249 | 265 | .expected_sr_errors = 1, |
| 250 | 266 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 251 | 267 | { XE_RTP_NAME("basic-1"), |
| @@ -265,7 +281,8 @@ static const struct rtp_test_case cases[] = { · 13 unmodified lines | ||
| 265 | 281 | .expected_reg = REGULAR_REG1, |
| 266 | 282 | .expected_set_bits = REG_BIT(0), |
| 267 | 283 | .expected_clr_bits = REG_BIT(0), |
| 268 | − .expected_count = 1, | |
| 284 | + .expected_active = BIT(0) | BIT(1) | BIT(2), | |
| 285 | + .expected_count_sr_entries = 1, | |
| 269 | 286 | .expected_sr_errors = 2, |
| 270 | 287 | .entries = (const struct xe_rtp_entry_sr[]) { |
| 271 | 288 | { XE_RTP_NAME("basic-1"), |
| @@ -287,28 +304,35 @@ static const struct rtp_test_case cases[] = { · 15 unmodified lines | ||
| 287 | 304 | }, |
| 288 | 305 | }; |
| 289 | 306 | |
| 290 | −static void xe_rtp_process_tests(struct kunit *test) | |
| 307 | +static void xe_rtp_process_to_sr_tests(struct kunit *test) | |
| 291 | 308 | { |
| 292 | − const struct rtp_test_case *param = test->param_value; | |
| 309 | + const struct rtp_to_sr_test_case *param = test->param_value; | |
| 293 | 310 | struct xe_device *xe = test->priv; |
| 294 | 311 | struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; |
| 295 | 312 | struct xe_reg_sr *reg_sr = >->reg_sr; |
| 296 | 313 | const struct xe_reg_sr_entry *sre, *sr_entry = NULL; |
| 297 | 314 | struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); |
| 298 | − unsigned long idx, count = 0; | |
| 315 | + unsigned long idx, count_sr_entries = 0, count_rtp_entries = 0, active = 0; | |
| 316 | + | |
| 317 | + xe_reg_sr_init(reg_sr, "xe_rtp_to_sr_tests", xe); | |
| 318 | + | |
| 319 | + while (param->entries[count_rtp_entries].rules) | |
| 320 | + count_rtp_entries++; | |
| 299 | 321 | |
| 300 | − xe_reg_sr_init(reg_sr, "xe_rtp_tests", xe); | |
| 322 | + xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries); | |
| 301 | 323 | xe_rtp_process_to_sr(&ctx, param->entries, reg_sr); |
| 302 | 324 | |
| 303 | 325 | xa_for_each(®_sr->xa, idx, sre) { |
| 304 | 326 | if (idx == param->expected_reg.addr) |
| 305 | 327 | sr_entry = sre; |
| 306 | 328 | |
| 307 | − count++; | |
| 329 | + count_sr_entries++; | |
| 308 | 330 | } |
| 309 | 331 | |
| 310 | − KUNIT_EXPECT_EQ(test, count, param->expected_count); | |
| 311 | − if (count) { | |
| 332 | + KUNIT_EXPECT_EQ(test, active, param->expected_active); | |
| 333 | + | |
| 334 | + KUNIT_EXPECT_EQ(test, count_sr_entries, param->expected_count_sr_entries); | |
| 335 | + if (count_sr_entries) { | |
| 312 | 336 | KUNIT_EXPECT_EQ(test, sr_entry->clr_bits, param->expected_clr_bits); |
| 313 | 337 | KUNIT_EXPECT_EQ(test, sr_entry->set_bits, param->expected_set_bits); |
| 314 | 338 | KUNIT_EXPECT_EQ(test, sr_entry->reg.raw, param->expected_reg.raw); |
| @@ -319,12 +343,162 @@ static void xe_rtp_process_tests(struct kunit *test) · 4 unmodified lines | ||
| 319 | 343 | KUNIT_EXPECT_EQ(test, reg_sr->errors, param->expected_sr_errors); |
| 320 | 344 | } |
| 321 | 345 | |
| 346 | +/* | |
| 347 | + * Entries below follow the logic used with xe_wa_oob.rules: | |
| 348 | + * 1) Entries with empty name are OR'ed: all entries marked active since the | |
| 349 | + * last entry with a name | |
| 350 | + * 2) There are no action associated with rules | |
| 351 | + */ | |
| 352 | +static const struct rtp_test_case rtp_cases[] = { | |
| 353 | + { | |
| 354 | + .name = "active1", | |
| 355 | + .expected_active = BIT(0), | |
| 356 | + .entries = (const struct xe_rtp_entry[]) { | |
| 357 | + { XE_RTP_NAME("r1"), | |
| 358 | + XE_RTP_RULES(FUNC(match_yes)), | |
| 359 | + }, | |
| 360 | + {} | |
| 361 | + }, | |
| 362 | + }, | |
| 363 | + { | |
| 364 | + .name = "active2", | |
| 365 | + .expected_active = BIT(0) | BIT(1), | |
| 366 | + .entries = (const struct xe_rtp_entry[]) { | |
| 367 | + { XE_RTP_NAME("r1"), | |
| 368 | + XE_RTP_RULES(FUNC(match_yes)), | |
| 369 | + }, | |
| 370 | + { XE_RTP_NAME("r2"), | |
| 371 | + XE_RTP_RULES(FUNC(match_yes)), | |
| 372 | + }, | |
| 373 | + {} | |
| 374 | + }, | |
| 375 | + }, | |
| 376 | + { | |
| 377 | + .name = "active-inactive", | |
| 378 | + .expected_active = BIT(0), | |
| 379 | + .entries = (const struct xe_rtp_entry[]) { | |
| 380 | + { XE_RTP_NAME("r1"), | |
| 381 | + XE_RTP_RULES(FUNC(match_yes)), | |
| 382 | + }, | |
| 383 | + { XE_RTP_NAME("r2"), | |
| 384 | + XE_RTP_RULES(FUNC(match_no)), | |
| 385 | + }, | |
| 386 | + {} | |
| 387 | + }, | |
| 388 | + }, | |
| 389 | + { | |
| 390 | + .name = "inactive-active", | |
| 391 | + .expected_active = BIT(1), | |
| 392 | + .entries = (const struct xe_rtp_entry[]) { | |
| 393 | + { XE_RTP_NAME("r1"), | |
| 394 | + XE_RTP_RULES(FUNC(match_no)), | |
| 395 | + }, | |
| 396 | + { XE_RTP_NAME("r2"), | |
| 397 | + XE_RTP_RULES(FUNC(match_yes)), | |
| 398 | + }, | |
| 399 | + {} | |
| 400 | + }, | |
| 401 | + }, | |
| 402 | + { | |
| 403 | + .name = "inactive-1st_or_active-inactive", | |
| 404 | + .expected_active = BIT(1), | |
| 405 | + .entries = (const struct xe_rtp_entry[]) { | |
| 406 | + { XE_RTP_NAME("r1"), | |
| 407 | + XE_RTP_RULES(FUNC(match_no)), | |
| 408 | + }, | |
| 409 | + { XE_RTP_NAME("r2_or_conditions"), | |
| 410 | + XE_RTP_RULES(FUNC(match_yes), OR, | |
| 411 | + FUNC(match_no), OR, | |
| 412 | + FUNC(match_no)) }, | |
| 413 | + { XE_RTP_NAME("r3"), | |
| 414 | + XE_RTP_RULES(FUNC(match_no)), | |
| 415 | + }, | |
| 416 | + {} | |
| 417 | + }, | |
| 418 | + }, | |
| 419 | + { | |
| 420 | + .name = "inactive-2nd_or_active-inactive", | |
| 421 | + .expected_active = BIT(1), | |
| 422 | + .entries = (const struct xe_rtp_entry[]) { | |
| 423 | + { XE_RTP_NAME("r1"), | |
| 424 | + XE_RTP_RULES(FUNC(match_no)), | |
| 425 | + }, | |
| 426 | + { XE_RTP_NAME("r2_or_conditions"), | |
| 427 | + XE_RTP_RULES(FUNC(match_no), OR, | |
| 428 | + FUNC(match_yes), OR, | |
| 429 | + FUNC(match_no)) }, | |
| 430 | + { XE_RTP_NAME("r3"), | |
| 431 | + XE_RTP_RULES(FUNC(match_no)), | |
| 432 | + }, | |
| 433 | + {} | |
| 434 | + }, | |
| 435 | + }, | |
| 436 | + { | |
| 437 | + .name = "inactive-last_or_active-inactive", | |
| 438 | + .expected_active = BIT(1), | |
| 439 | + .entries = (const struct xe_rtp_entry[]) { | |
| 440 | + { XE_RTP_NAME("r1"), | |
| 441 | + XE_RTP_RULES(FUNC(match_no)), | |
| 442 | + }, | |
| 443 | + { XE_RTP_NAME("r2_or_conditions"), | |
| 444 | + XE_RTP_RULES(FUNC(match_no), OR, | |
| 445 | + FUNC(match_no), OR, | |
| 446 | + FUNC(match_yes)) }, | |
| 447 | + { XE_RTP_NAME("r3"), | |
| 448 | + XE_RTP_RULES(FUNC(match_no)), | |
| 449 | + }, | |
| 450 | + {} | |
| 451 | + }, | |
| 452 | + }, | |
| 453 | + { | |
| 454 | + .name = "inactive-no_or_active-inactive", | |
| 455 | + .expected_active = 0, | |
| 456 | + .entries = (const struct xe_rtp_entry[]) { | |
| 457 | + { XE_RTP_NAME("r1"), | |
| 458 | + XE_RTP_RULES(FUNC(match_no)), | |
| 459 | + }, | |
| 460 | + { XE_RTP_NAME("r2_or_conditions"), | |
| 461 | + XE_RTP_RULES(FUNC(match_no), OR, | |
| 462 | + FUNC(match_no), OR, | |
| 463 | + FUNC(match_no)) }, | |
| 464 | + { XE_RTP_NAME("r3"), | |
| 465 | + XE_RTP_RULES(FUNC(match_no)), | |
| 466 | + }, | |
| 467 | + {} | |
| 468 | + }, | |
| 469 | + }, | |
| 470 | +}; | |
| 471 | + | |
| 472 | +static void xe_rtp_process_tests(struct kunit *test) | |
| 473 | +{ | |
| 474 | + const struct rtp_test_case *param = test->param_value; | |
| 475 | + struct xe_device *xe = test->priv; | |
| 476 | + struct xe_gt *gt = xe_device_get_root_tile(xe)->primary_gt; | |
| 477 | + struct xe_rtp_process_ctx ctx = XE_RTP_PROCESS_CTX_INITIALIZER(gt); | |
| 478 | + unsigned long count_rtp_entries = 0, active = 0; | |
| 479 | + | |
| 480 | + while (param->entries[count_rtp_entries].rules) | |
| 481 | + count_rtp_entries++; | |
| 482 | + | |
| 483 | + xe_rtp_process_ctx_enable_active_tracking(&ctx, &active, count_rtp_entries); | |
| 484 | + xe_rtp_process(&ctx, param->entries); | |
| 485 | + | |
| 486 | + KUNIT_EXPECT_EQ(test, active, param->expected_active); | |
| 487 | +} | |
| 488 | + | |
| 489 | +static void rtp_to_sr_desc(const struct rtp_to_sr_test_case *t, char *desc) | |
| 490 | +{ | |
| 491 | + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); | |
| 492 | +} | |
| 493 | + | |
| 494 | +KUNIT_ARRAY_PARAM(rtp_to_sr, rtp_to_sr_cases, rtp_to_sr_desc); | |
| 495 | + | |
| 322 | 496 | static void rtp_desc(const struct rtp_test_case *t, char *desc) |
| 323 | 497 | { |
| 324 | 498 | strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); |
| 325 | 499 | } |
| 326 | 500 | |
| 327 | −KUNIT_ARRAY_PARAM(rtp, cases, rtp_desc); | |
| 501 | +KUNIT_ARRAY_PARAM(rtp, rtp_cases, rtp_desc); | |
| 328 | 502 | |
| 329 | 503 | static int xe_rtp_test_init(struct kunit *test) |
| 330 | 504 | { |
| @@ -357,6 +531,7 @@ static void xe_rtp_test_exit(struct kunit *test) · 26 unmodified lines | ||
| 357 | 531 | } |
| 358 | 532 | |
| 359 | 533 | static struct kunit_case xe_rtp_tests[] = { |
| 534 | + KUNIT_CASE_PARAM(xe_rtp_process_to_sr_tests, rtp_to_sr_gen_params), | |
| 360 | 535 | KUNIT_CASE_PARAM(xe_rtp_process_tests, rtp_gen_params), |
| 361 | 536 | {} |
| 362 | 537 | }; |
| @@ -9,8 +9,8 @@ · 8 unmodified lines | ||
| 9 | 9 | #include <linux/types.h> |
| 10 | 10 | |
| 11 | 11 | #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) |
| 12 | −#include <linux/sched.h> | |
| 13 | 12 | #include <kunit/test.h> |
| 13 | +#include <kunit/test-bug.h> | |
| 14 | 14 | |
| 15 | 15 | /* |
| 16 | 16 | * Each test that provides a kunit private test structure, place a test id |
| @@ -31,8 +31,6 @@ struct xe_test_priv { · 14 unmodified lines | ||
| 31 | 31 | |
| 32 | 32 | #define XE_TEST_DECLARE(x) x |
| 33 | 33 | #define XE_TEST_ONLY(x) unlikely(x) |
| 34 | −#define XE_TEST_EXPORT | |
| 35 | −#define xe_cur_kunit() current->kunit_test | |
| 36 | 34 | |
| 37 | 35 | /** |
| 38 | 36 | * xe_cur_kunit_priv - Obtain the struct xe_test_priv pointed to by |
| @@ -48,10 +46,10 @@ xe_cur_kunit_priv(enum xe_test_priv_id id) · 9 unmodified lines | ||
| 48 | 46 | { |
| 49 | 47 | struct xe_test_priv *priv; |
| 50 | 48 | |
| 51 | − if (!xe_cur_kunit()) | |
| 49 | + if (!kunit_get_current_test()) | |
| 52 | 50 | return NULL; |
| 53 | 51 | |
| 54 | − priv = xe_cur_kunit()->priv; | |
| 52 | + priv = kunit_get_current_test()->priv; | |
| 55 | 53 | return priv->id == id ? priv : NULL; |
| 56 | 54 | } |
| 57 | 55 | |
| @@ -59,8 +57,6 @@ xe_cur_kunit_priv(enum xe_test_priv_id id) · 1 unmodified line | ||
| 59 | 57 | |
| 60 | 58 | #define XE_TEST_DECLARE(x) |
| 61 | 59 | #define XE_TEST_ONLY(x) 0 |
| 62 | −#define XE_TEST_EXPORT static | |
| 63 | −#define xe_cur_kunit() NULL | |
| 64 | 60 | #define xe_cur_kunit_priv(_id) NULL |
| 65 | 61 | |
| 66 | 62 | #endif |
| @@ -74,6 +74,7 @@ static const struct platform_test_case cases[] = { · 73 unmodified lines | ||
| 74 | 74 | GMDID_CASE(METEORLAKE, 1274, A0, 1300, A0), |
| 75 | 75 | GMDID_CASE(LUNARLAKE, 2004, A0, 2000, A0), |
| 76 | 76 | GMDID_CASE(LUNARLAKE, 2004, B0, 2000, A0), |
| 77 | + GMDID_CASE(BATTLEMAGE, 2001, A0, 1301, A1), | |
| 77 | 78 | }; |
| 78 | 79 | |
| 79 | 80 | static void platform_desc(const struct platform_test_case *t, char *desc) |
| @@ -1264,13 +1264,14 @@ struct xe_bo *___xe_bo_create_locked(struct xe_device *xe, struct xe_bo *bo, · 1263 unmodified lines | ||
| 1264 | 1264 | if (flags & (XE_BO_FLAG_VRAM_MASK | XE_BO_FLAG_STOLEN) && |
| 1265 | 1265 | !(flags & XE_BO_FLAG_IGNORE_MIN_PAGE_SIZE) && |
| 1266 | 1266 | ((xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K) || |
| 1267 | − (flags & XE_BO_NEEDS_64K))) { | |
| 1268 | − aligned_size = ALIGN(size, SZ_64K); | |
| 1267 | + (flags & (XE_BO_FLAG_NEEDS_64K | XE_BO_FLAG_NEEDS_2M)))) { | |
| 1268 | + size_t align = flags & XE_BO_FLAG_NEEDS_2M ? SZ_2M : SZ_64K; | |
| 1269 | + | |
| 1270 | + aligned_size = ALIGN(size, align); | |
| 1269 | 1271 | if (type != ttm_bo_type_device) |
| 1270 | − size = ALIGN(size, SZ_64K); | |
| 1272 | + size = ALIGN(size, align); | |
| 1271 | 1273 | flags |= XE_BO_FLAG_INTERNAL_64K; |
| 1272 | − alignment = SZ_64K >> PAGE_SHIFT; | |
| 1273 | − | |
| 1274 | + alignment = align >> PAGE_SHIFT; | |
| 1274 | 1275 | } else { |
| 1275 | 1276 | aligned_size = ALIGN(size, SZ_4K); |
| 1276 | 1277 | flags &= ~XE_BO_FLAG_INTERNAL_64K; |
| @@ -36,8 +36,9 @@ · 35 unmodified lines | ||
| 36 | 36 | #define XE_BO_FLAG_PAGETABLE BIT(12) |
| 37 | 37 | #define XE_BO_FLAG_NEEDS_CPU_ACCESS BIT(13) |
| 38 | 38 | #define XE_BO_FLAG_NEEDS_UC BIT(14) |
| 39 | −#define XE_BO_NEEDS_64K BIT(15) | |
| 40 | −#define XE_BO_FLAG_GGTT_INVALIDATE BIT(16) | |
| 39 | +#define XE_BO_FLAG_NEEDS_64K BIT(15) | |
| 40 | +#define XE_BO_FLAG_NEEDS_2M BIT(16) | |
| 41 | +#define XE_BO_FLAG_GGTT_INVALIDATE BIT(17) | |
| 41 | 42 | /* this one is trigger internally only */ |
| 42 | 43 | #define XE_BO_FLAG_INTERNAL_TEST BIT(30) |
| 43 | 44 | #define XE_BO_FLAG_INTERNAL_64K BIT(31) |
| @@ -58,6 +58,8 @@ struct xe_bo { · 57 unmodified lines | ||
| 58 | 58 | #endif |
| 59 | 59 | /** @freed: List node for delayed put. */ |
| 60 | 60 | struct llist_node freed; |
| 61 | + /** @update_index: Update index if PT BO */ | |
| 62 | + int update_index; | |
| 61 | 63 | /** @created: Whether the bo has passed initial creation */ |
| 62 | 64 | bool created; |
| 63 | 65 | |
| @@ -171,7 +171,6 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump, · 170 unmodified lines | ||
| 171 | 171 | u32 adj_logical_mask = q->logical_mask; |
| 172 | 172 | u32 width_mask = (0x1 << q->width) - 1; |
| 173 | 173 | const char *process_name = "no process"; |
| 174 | − struct task_struct *task = NULL; | |
| 175 | 174 | |
| 176 | 175 | int i; |
| 177 | 176 | bool cookie; |
| @@ -179,14 +178,9 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump, · 1 unmodified line | ||
| 179 | 178 | ss->snapshot_time = ktime_get_real(); |
| 180 | 179 | ss->boot_time = ktime_get_boottime(); |
| 181 | 180 | |
| 182 | − if (q->vm && q->vm->xef) { | |
| 183 | − task = get_pid_task(q->vm->xef->drm->pid, PIDTYPE_PID); | |
| 184 | − if (task) | |
| 185 | − process_name = task->comm; | |
| 186 | − } | |
| 181 | + if (q->vm && q->vm->xef) | |
| 182 | + process_name = q->vm->xef->process_name; | |
| 187 | 183 | strscpy(ss->process_name, process_name); |
| 188 | − if (task) | |
| 189 | − put_task_struct(task); | |
| 190 | 184 | |
| 191 | 185 | ss->gt = q->gt; |
| 192 | 186 | INIT_WORK(&ss->work, xe_devcoredump_deferred_snap_work); |
| @@ -54,6 +54,9 @@ · 53 unmodified lines | ||
| 54 | 54 | #include "xe_vm.h" |
| 55 | 55 | #include "xe_vram.h" |
| 56 | 56 | #include "xe_wait_user_fence.h" |
| 57 | +#include "xe_wa.h" | |
| 58 | + | |
| 59 | +#include <generated/xe_wa_oob.h> | |
| 57 | 60 | |
| 58 | 61 | static int xe_file_open(struct drm_device *dev, struct drm_file *file) |
| 59 | 62 | { |
| @@ -61,6 +64,7 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file) · 1 unmodified line | ||
| 61 | 64 | struct xe_drm_client *client; |
| 62 | 65 | struct xe_file *xef; |
| 63 | 66 | int ret = -ENOMEM; |
| 67 | + struct task_struct *task = NULL; | |
| 64 | 68 | |
| 65 | 69 | xef = kzalloc(sizeof(*xef), GFP_KERNEL); |
| 66 | 70 | if (!xef) |
| @@ -87,9 +91,63 @@ static int xe_file_open(struct drm_device *dev, struct drm_file *file) · 20 unmodified lines | ||
| 87 | 91 | spin_unlock(&xe->clients.lock); |
| 88 | 92 | |
| 89 | 93 | file->driver_priv = xef; |
| 94 | + kref_init(&xef->refcount); | |
| 95 | + | |
| 96 | + task = get_pid_task(rcu_access_pointer(file->pid), PIDTYPE_PID); | |
| 97 | + if (task) { | |
| 98 | + xef->process_name = kstrdup(task->comm, GFP_KERNEL); | |
| 99 | + xef->pid = task->pid; | |
| 100 | + put_task_struct(task); | |
| 101 | + } | |
| 102 | + | |
| 90 | 103 | return 0; |
| 91 | 104 | } |
| 92 | 105 | |
| 106 | +static void xe_file_destroy(struct kref *ref) | |
| 107 | +{ | |
| 108 | + struct xe_file *xef = container_of(ref, struct xe_file, refcount); | |
| 109 | + struct xe_device *xe = xef->xe; | |
| 110 | + | |
| 111 | + xa_destroy(&xef->exec_queue.xa); | |
| 112 | + mutex_destroy(&xef->exec_queue.lock); | |
| 113 | + xa_destroy(&xef->vm.xa); | |
| 114 | + mutex_destroy(&xef->vm.lock); | |
| 115 | + | |
| 116 | + spin_lock(&xe->clients.lock); | |
| 117 | + xe->clients.count--; | |
| 118 | + spin_unlock(&xe->clients.lock); | |
| 119 | + | |
| 120 | + xe_drm_client_put(xef->client); | |
| 121 | + kfree(xef->process_name); | |
| 122 | + kfree(xef); | |
| 123 | +} | |
| 124 | + | |
| 125 | +/** | |
| 126 | + * xe_file_get() - Take a reference to the xe file object | |
| 127 | + * @xef: Pointer to the xe file | |
| 128 | + * | |
| 129 | + * Anyone with a pointer to xef must take a reference to the xe file | |
| 130 | + * object using this call. | |
| 131 | + * | |
| 132 | + * Return: xe file pointer | |
| 133 | + */ | |
| 134 | +struct xe_file *xe_file_get(struct xe_file *xef) | |
| 135 | +{ | |
| 136 | + kref_get(&xef->refcount); | |
| 137 | + return xef; | |
| 138 | +} | |
| 139 | + | |
| 140 | +/** | |
| 141 | + * xe_file_put() - Drop a reference to the xe file object | |
| 142 | + * @xef: Pointer to the xe file | |
| 143 | + * | |
| 144 | + * Used to drop reference to the xef object | |
| 145 | + */ | |
| 146 | +void xe_file_put(struct xe_file *xef) | |
| 147 | +{ | |
| 148 | + kref_put(&xef->refcount, xe_file_destroy); | |
| 149 | +} | |
| 150 | + | |
| 93 | 151 | static void xe_file_close(struct drm_device *dev, struct drm_file *file) |
| 94 | 152 | { |
| 95 | 153 | struct xe_device *xe = to_xe_device(dev); |
| @@ -98,6 +156,8 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file) · 2 unmodified lines | ||
| 98 | 156 | struct xe_exec_queue *q; |
| 99 | 157 | unsigned long idx; |
| 100 | 158 | |
| 159 | + xe_pm_runtime_get(xe); | |
| 160 | + | |
| 101 | 161 | /* |
| 102 | 162 | * No need for exec_queue.lock here as there is no contention for it |
| 103 | 163 | * when FD is closing as IOCTLs presumably can't be modifying the |
| @@ -108,21 +168,14 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file) · 4 unmodified lines | ||
| 108 | 168 | xe_exec_queue_kill(q); |
| 109 | 169 | xe_exec_queue_put(q); |
| 110 | 170 | } |
| 111 | − xa_destroy(&xef->exec_queue.xa); | |
| 112 | − mutex_destroy(&xef->exec_queue.lock); | |
| 113 | 171 | mutex_lock(&xef->vm.lock); |
| 114 | 172 | xa_for_each(&xef->vm.xa, idx, vm) |
| 115 | 173 | xe_vm_close_and_put(vm); |
| 116 | 174 | mutex_unlock(&xef->vm.lock); |
| 117 | − xa_destroy(&xef->vm.xa); | |
| 118 | − mutex_destroy(&xef->vm.lock); | |
| 119 | 175 | |
| 120 | − spin_lock(&xe->clients.lock); | |
| 121 | − xe->clients.count--; | |
| 122 | − spin_unlock(&xe->clients.lock); | |
| 176 | + xe_file_put(xef); | |
| 123 | 177 | |
| 124 | − xe_drm_client_put(xef->client); | |
| 125 | − kfree(xef); | |
| 178 | + xe_pm_runtime_put(xe); | |
| 126 | 179 | } |
| 127 | 180 | |
| 128 | 181 | static const struct drm_ioctl_desc xe_ioctls[] = { |
| @@ -744,13 +797,22 @@ void xe_device_shutdown(struct xe_device *xe) · 615 unmodified lines | ||
| 744 | 797 | { |
| 745 | 798 | } |
| 746 | 799 | |
| 800 | +/** | |
| 801 | + * xe_device_wmb() - Device specific write memory barrier | |
| 802 | + * @xe: the &xe_device | |
| 803 | + * | |
| 804 | + * While wmb() is sufficient for a barrier if we use system memory, on discrete | |
| 805 | + * platforms with device memory we additionally need to issue a register write. | |
| 806 | + * Since it doesn't matter which register we write to, use the read-only VF_CAP | |
| 807 | + * register that is also marked as accessible by the VFs. | |
| 808 | + */ | |
| 747 | 809 | void xe_device_wmb(struct xe_device *xe) |
| 748 | 810 | { |
| 749 | 811 | struct xe_gt *gt = xe_root_mmio_gt(xe); |
| 750 | 812 | |
| 751 | 813 | wmb(); |
| 752 | 814 | if (IS_DGFX(xe)) |
| 753 | − xe_mmio_write32(gt, SOFTWARE_FLAGS_SPR33, 0); | |
| 815 | + xe_mmio_write32(gt, VF_CAP_REG, 0); | |
| 754 | 816 | } |
| 755 | 817 | |
| 756 | 818 | /** |
| @@ -779,6 +841,11 @@ void xe_device_td_flush(struct xe_device *xe) · 22 unmodified lines | ||
| 779 | 841 | if (!IS_DGFX(xe) || GRAPHICS_VER(xe) < 20) |
| 780 | 842 | return; |
| 781 | 843 | |
| 844 | + if (XE_WA(xe_root_mmio_gt(xe), 16023588340)) { | |
| 845 | + xe_device_l2_flush(xe); | |
| 846 | + return; | |
| 847 | + } | |
| 848 | + | |
| 782 | 849 | for_each_gt(gt, xe, id) { |
| 783 | 850 | if (xe_gt_is_media_type(gt)) |
| 784 | 851 | continue; |
| @@ -802,6 +869,30 @@ void xe_device_td_flush(struct xe_device *xe) · 17 unmodified lines | ||
| 802 | 869 | } |
| 803 | 870 | } |
| 804 | 871 | |
| 872 | +void xe_device_l2_flush(struct xe_device *xe) | |
| 873 | +{ | |
| 874 | + struct xe_gt *gt; | |
| 875 | + int err; | |
| 876 | + | |
| 877 | + gt = xe_root_mmio_gt(xe); | |
| 878 | + | |
| 879 | + if (!XE_WA(gt, 16023588340)) | |
| 880 | + return; | |
| 881 | + | |
| 882 | + err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | |
| 883 | + if (err) | |
| 884 | + return; | |
| 885 | + | |
| 886 | + spin_lock(>->global_invl_lock); | |
| 887 | + xe_mmio_write32(gt, XE2_GLOBAL_INVAL, 0x1); | |
| 888 | + | |
| 889 | + if (xe_mmio_wait32(gt, XE2_GLOBAL_INVAL, 0x1, 0x0, 150, NULL, true)) | |
| 890 | + xe_gt_err_once(gt, "Global invalidation timeout\n"); | |
| 891 | + spin_unlock(>->global_invl_lock); | |
| 892 | + | |
| 893 | + xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); | |
| 894 | +} | |
| 895 | + | |
| 805 | 896 | u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size) |
| 806 | 897 | { |
| 807 | 898 | return xe_device_has_flat_ccs(xe) ? |
| @@ -20,6 +20,11 @@ static inline struct xe_device *pdev_to_xe_device(struct pci_dev *pdev) · 19 unmodified lines | ||
| 20 | 20 | return pci_get_drvdata(pdev); |
| 21 | 21 | } |
| 22 | 22 | |
| 23 | +static inline struct xe_device *xe_device_const_cast(const struct xe_device *xe) | |
| 24 | +{ | |
| 25 | + return (struct xe_device *)xe; | |
| 26 | +} | |
| 27 | + | |
| 23 | 28 | static inline struct xe_device *ttm_to_xe_device(struct ttm_device *ttm) |
| 24 | 29 | { |
| 25 | 30 | return container_of(ttm, struct xe_device, ttm); |
| @@ -162,6 +167,7 @@ u64 xe_device_canonicalize_addr(struct xe_device *xe, u64 address); · 136 unmodified lines | ||
| 162 | 167 | u64 xe_device_uncanonicalize_addr(struct xe_device *xe, u64 address); |
| 163 | 168 | |
| 164 | 169 | void xe_device_td_flush(struct xe_device *xe); |
| 170 | +void xe_device_l2_flush(struct xe_device *xe); | |
| 165 | 171 | |
| 166 | 172 | static inline bool xe_device_wedged(struct xe_device *xe) |
| 167 | 173 | { |
| @@ -170,4 +176,7 @@ static inline bool xe_device_wedged(struct xe_device *xe) · 2 unmodified lines | ||
| 170 | 176 | |
| 171 | 177 | void xe_device_declare_wedged(struct xe_device *xe); |
| 172 | 178 | |
| 179 | +struct xe_file *xe_file_get(struct xe_file *xef); | |
| 180 | +void xe_file_put(struct xe_file *xef); | |
| 181 | + | |
| 173 | 182 | #endif |
| @@ -23,6 +23,10 @@ · 22 unmodified lines | ||
| 23 | 23 | #include "xe_sriov_types.h" |
| 24 | 24 | #include "xe_step_types.h" |
| 25 | 25 | |
| 26 | +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG) | |
| 27 | +#define TEST_VM_OPS_ERROR | |
| 28 | +#endif | |
| 29 | + | |
| 26 | 30 | #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY) |
| 27 | 31 | #include "soc/intel_pch.h" |
| 28 | 32 | #include "intel_display_core.h" |
| @@ -40,6 +44,7 @@ struct xe_pat_ops; · 11 unmodified lines | ||
| 40 | 44 | #define MEDIA_VERx100(xe) ((xe)->info.media_verx100) |
| 41 | 45 | #define IS_DGFX(xe) ((xe)->info.is_dgfx) |
| 42 | 46 | #define HAS_HECI_GSCFI(xe) ((xe)->info.has_heci_gscfi) |
| 47 | +#define HAS_HECI_CSCFI(xe) ((xe)->info.has_heci_cscfi) | |
| 43 | 48 | |
| 44 | 49 | #define XE_VRAM_FLAGS_NEED64K BIT(0) |
| 45 | 50 | |
| @@ -285,6 +290,8 @@ struct xe_device { · 239 unmodified lines | ||
| 285 | 290 | u8 skip_pcode:1; |
| 286 | 291 | /** @info.has_heci_gscfi: device has heci gscfi */ |
| 287 | 292 | u8 has_heci_gscfi:1; |
| 293 | + /** @info.has_heci_cscfi: device has heci cscfi */ | |
| 294 | + u8 has_heci_cscfi:1; | |
| 288 | 295 | /** @info.skip_guc_pc: Skip GuC based PM feature init */ |
| 289 | 296 | u8 skip_guc_pc:1; |
| 290 | 297 | /** @info.has_atomic_enable_pte_bit: Device has atomic enable PTE bit */ |
| @@ -477,6 +484,14 @@ struct xe_device { · 186 unmodified lines | ||
| 477 | 484 | int mode; |
| 478 | 485 | } wedged; |
| 479 | 486 | |
| 487 | +#ifdef TEST_VM_OPS_ERROR | |
| 488 | + /** | |
| 489 | + * @vm_inject_error_position: inject errors at different places in VM | |
| 490 | + * bind IOCTL based on this value | |
| 491 | + */ | |
| 492 | + u8 vm_inject_error_position; | |
| 493 | +#endif | |
| 494 | + | |
| 480 | 495 | /* private: */ |
| 481 | 496 | |
| 482 | 497 | #if IS_ENABLED(CONFIG_DRM_XE_DISPLAY) |
| @@ -566,6 +581,21 @@ struct xe_file { · 83 unmodified lines | ||
| 566 | 581 | |
| 567 | 582 | /** @client: drm client */ |
| 568 | 583 | struct xe_drm_client *client; |
| 584 | + | |
| 585 | + /** | |
| 586 | + * @process_name: process name for file handle, used to safely output | |
| 587 | + * during error situations where xe file can outlive process | |
| 588 | + */ | |
| 589 | + char *process_name; | |
| 590 | + | |
| 591 | + /** | |
| 592 | + * @pid: pid for file handle, used to safely output uring error | |
| 593 | + * situations where xe file can outlive process | |
| 594 | + */ | |
| 595 | + pid_t pid; | |
| 596 | + | |
| 597 | + /** @refcount: ref count of this xe file */ | |
| 598 | + struct kref refcount; | |
| 569 | 599 | }; |
| 570 | 600 | |
| 571 | 601 | #endif |
| @@ -251,11 +251,8 @@ static void show_run_ticks(struct drm_printer *p, struct drm_file *file) · 250 unmodified lines | ||
| 251 | 251 | |
| 252 | 252 | /* Accumulate all the exec queues from this client */ |
| 253 | 253 | mutex_lock(&xef->exec_queue.lock); |
| 254 | − xa_for_each(&xef->exec_queue.xa, i, q) { | |
| 254 | + xa_for_each(&xef->exec_queue.xa, i, q) | |
| 255 | 255 | xe_exec_queue_update_run_ticks(q); |
| 256 | − xef->run_ticks[q->class] += q->run_ticks - q->old_run_ticks; | |
| 257 | − q->old_run_ticks = q->run_ticks; | |
| 258 | − } | |
| 259 | 256 | mutex_unlock(&xef->exec_queue.lock); |
| 260 | 257 | |
| 261 | 258 | /* Get the total GPU cycles */ |
| @@ -37,6 +37,10 @@ static void __xe_exec_queue_free(struct xe_exec_queue *q) · 36 unmodified lines | ||
| 37 | 37 | { |
| 38 | 38 | if (q->vm) |
| 39 | 39 | xe_vm_put(q->vm); |
| 40 | + | |
| 41 | + if (q->xef) | |
| 42 | + xe_file_put(q->xef); | |
| 43 | + | |
| 40 | 44 | kfree(q); |
| 41 | 45 | } |
| 42 | 46 | |
| @@ -649,6 +653,7 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, · 606 unmodified lines | ||
| 649 | 653 | goto kill_exec_queue; |
| 650 | 654 | |
| 651 | 655 | args->exec_queue_id = id; |
| 656 | + q->xef = xe_file_get(xef); | |
| 652 | 657 | |
| 653 | 658 | return 0; |
| 654 | 659 | |
| @@ -762,6 +767,7 @@ bool xe_exec_queue_is_idle(struct xe_exec_queue *q) · 107 unmodified lines | ||
| 762 | 767 | */ |
| 763 | 768 | void xe_exec_queue_update_run_ticks(struct xe_exec_queue *q) |
| 764 | 769 | { |
| 770 | + struct xe_file *xef; | |
| 765 | 771 | struct xe_lrc *lrc; |
| 766 | 772 | u32 old_ts, new_ts; |
| 767 | 773 | |
| @@ -773,6 +779,8 @@ void xe_exec_queue_update_run_ticks(struct xe_exec_queue *q) · 5 unmodified lines | ||
| 773 | 779 | if (!q->vm || !q->vm->xef) |
| 774 | 780 | return; |
| 775 | 781 | |
| 782 | + xef = q->vm->xef; | |
| 783 | + | |
| 776 | 784 | /* |
| 777 | 785 | * Only sample the first LRC. For parallel submission, all of them are |
| 778 | 786 | * scheduled together and we compensate that below by multiplying by |
| @@ -783,7 +791,7 @@ void xe_exec_queue_update_run_ticks(struct xe_exec_queue *q) · 4 unmodified lines | ||
| 783 | 791 | */ |
| 784 | 792 | lrc = q->lrc[0]; |
| 785 | 793 | new_ts = xe_lrc_update_timestamp(lrc, &old_ts); |
| 786 | − q->run_ticks += (new_ts - old_ts) * q->width; | |
| 794 | + xef->run_ticks[q->class] += (new_ts - old_ts) * q->width; | |
| 787 | 795 | } |
| 788 | 796 | |
| 789 | 797 | void xe_exec_queue_kill(struct xe_exec_queue *q) |
| @@ -906,3 +914,26 @@ void xe_exec_queue_last_fence_set(struct xe_exec_queue *q, struct xe_vm *vm, · 116 unmodified lines | ||
| 906 | 914 | xe_exec_queue_last_fence_put(q, vm); |
| 907 | 915 | q->last_fence = dma_fence_get(fence); |
| 908 | 916 | } |
| 917 | + | |
| 918 | +/** | |
| 919 | + * xe_exec_queue_last_fence_test_dep - Test last fence dependency of queue | |
| 920 | + * @q: The exec queue | |
| 921 | + * @vm: The VM the engine does a bind or exec for | |
| 922 | + * | |
| 923 | + * Returns: | |
| 924 | + * -ETIME if there exists an unsignalled last fence dependency, zero otherwise. | |
| 925 | + */ | |
| 926 | +int xe_exec_queue_last_fence_test_dep(struct xe_exec_queue *q, struct xe_vm *vm) | |
| 927 | +{ | |
| 928 | + struct dma_fence *fence; | |
| 929 | + int err = 0; | |
| 930 | + | |
| 931 | + fence = xe_exec_queue_last_fence_get(q, vm); | |
| 932 | + if (fence) { | |
| 933 | + err = test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags) ? | |
| 934 | + 0 : -ETIME; | |
| 935 | + dma_fence_put(fence); | |
| 936 | + } | |
| 937 | + | |
| 938 | + return err; | |
| 939 | +} | |
| @@ -75,6 +75,8 @@ struct dma_fence *xe_exec_queue_last_fence_get(struct xe_exec_queue *e, · 74 unmodified lines | ||
| 75 | 75 | struct xe_vm *vm); |
| 76 | 76 | void xe_exec_queue_last_fence_set(struct xe_exec_queue *e, struct xe_vm *vm, |
| 77 | 77 | struct dma_fence *fence); |
| 78 | +int xe_exec_queue_last_fence_test_dep(struct xe_exec_queue *q, | |
| 79 | + struct xe_vm *vm); | |
| 78 | 80 | void xe_exec_queue_update_run_ticks(struct xe_exec_queue *q); |
| 79 | 81 | |
| 80 | 82 | #endif |
| @@ -38,6 +38,9 @@ enum xe_exec_queue_priority { · 37 unmodified lines | ||
| 38 | 38 | * a kernel object. |
| 39 | 39 | */ |
| 40 | 40 | struct xe_exec_queue { |
| 41 | + /** @xef: Back pointer to xe file if this is user created exec queue */ | |
| 42 | + struct xe_file *xef; | |
| 43 | + | |
| 41 | 44 | /** @gt: graphics tile this exec queue can submit to */ |
| 42 | 45 | struct xe_gt *gt; |
| 43 | 46 | /** |
| @@ -139,10 +142,6 @@ struct xe_exec_queue { · 95 unmodified lines | ||
| 139 | 142 | * Protected by @vm's resv. Unused if @vm == NULL. |
| 140 | 143 | */ |
| 141 | 144 | u64 tlb_flush_seqno; |
| 142 | − /** @old_run_ticks: prior hw engine class run time in ticks for this exec queue */ | |
| 143 | − u64 old_run_ticks; | |
| 144 | − /** @run_ticks: hw engine class run time in ticks for this exec queue */ | |
| 145 | − u64 run_ticks; | |
| 146 | 145 | /** @lrc: logical ring context for this exec queue */ |
| 147 | 146 | struct xe_lrc *lrc[]; |
| 148 | 147 | }; |
| @@ -172,9 +171,11 @@ struct xe_exec_queue_ops { · 23 unmodified lines | ||
| 172 | 171 | int (*suspend)(struct xe_exec_queue *q); |
| 173 | 172 | /** |
| 174 | 173 | * @suspend_wait: Wait for an exec queue to suspend executing, should be |
| 175 | − * call after suspend. | |
| 174 | + * call after suspend. In dma-fencing path thus must return within a | |
| 175 | + * reasonable amount of time. -ETIME return shall indicate an error | |
| 176 | + * waiting for suspend resulting in associated VM getting killed. | |
| 176 | 177 | */ |
| 177 | − void (*suspend_wait)(struct xe_exec_queue *q); | |
| 178 | + int (*suspend_wait)(struct xe_exec_queue *q); | |
| 178 | 179 | /** |
| 179 | 180 | * @resume: Resume exec queue execution, exec queue must be in a suspended |
| 180 | 181 | * state and dma fence returned from most recent suspend call must be |
| @@ -422,10 +422,11 @@ static int execlist_exec_queue_suspend(struct xe_exec_queue *q) · 421 unmodified lines | ||
| 422 | 422 | return 0; |
| 423 | 423 | } |
| 424 | 424 | |
| 425 | −static void execlist_exec_queue_suspend_wait(struct xe_exec_queue *q) | |
| 425 | +static int execlist_exec_queue_suspend_wait(struct xe_exec_queue *q) | |
| 426 | 426 | |
| 427 | 427 | { |
| 428 | 428 | /* NIY */ |
| 429 | + return 0; | |
| 429 | 430 | } |
| 430 | 431 | |
| 431 | 432 | static void execlist_exec_queue_resume(struct xe_exec_queue *q) |
| @@ -97,19 +97,27 @@ static int parse(FILE *input, FILE *csource, FILE *cheader) · 96 unmodified lines | ||
| 97 | 97 | |
| 98 | 98 | if (name) { |
| 99 | 99 | fprintf(cheader, "\tXE_WA_OOB_%s = %u,\n", name, idx); |
| 100 | − fprintf(csource, "{ XE_RTP_NAME(\"%s\"), XE_RTP_RULES(%s) },\n", | |
| 100 | + | |
| 101 | + /* Close previous entry before starting a new one */ | |
| 102 | + if (idx) | |
| 103 | + fprintf(csource, ") },\n"); | |
| 104 | + | |
| 105 | + fprintf(csource, "{ XE_RTP_NAME(\"%s\"),\n XE_RTP_RULES(%s", | |
| 101 | 106 | name, rules); |
| 107 | + idx++; | |
| 102 | 108 | } else { |
| 103 | − fprintf(csource, "{ XE_RTP_NAME(NULL), XE_RTP_RULES(%s) },\n", | |
| 104 | − rules); | |
| 109 | + fprintf(csource, ", OR,\n\t%s", rules); | |
| 105 | 110 | } |
| 106 | 111 | |
| 107 | − idx++; | |
| 108 | 112 | lineno++; |
| 109 | 113 | if (!is_continuation) |
| 110 | 114 | prev_name = name; |
| 111 | 115 | } |
| 112 | 116 | |
| 117 | + /* Close last entry */ | |
| 118 | + if (idx) | |
| 119 | + fprintf(csource, ") },\n"); | |
| 120 | + | |
| 113 | 121 | fprintf(cheader, "\t_XE_WA_OOB_COUNT = %u\n", idx); |
| 114 | 122 | |
| 115 | 123 | return 0; |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | ||
| 9 | 9 | |
| 10 | 10 | #include <drm/drm_managed.h> |
| 11 | 11 | #include <drm/xe_drm.h> |
| 12 | + | |
| 12 | 13 | #include <generated/xe_wa_oob.h> |
| 13 | 14 | |
| 14 | 15 | #include "instructions/xe_gfxpipe_commands.h" |
| @@ -95,6 +96,51 @@ void xe_gt_sanitize(struct xe_gt *gt) · 80 unmodified lines | ||
| 95 | 96 | gt->uc.guc.submission_state.enabled = false; |
| 96 | 97 | } |
| 97 | 98 | |
| 99 | +static void xe_gt_enable_host_l2_vram(struct xe_gt *gt) | |
| 100 | +{ | |
| 101 | + u32 reg; | |
| 102 | + int err; | |
| 103 | + | |
| 104 | + if (!XE_WA(gt, 16023588340)) | |
| 105 | + return; | |
| 106 | + | |
| 107 | + err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | |
| 108 | + if (WARN_ON(err)) | |
| 109 | + return; | |
| 110 | + | |
| 111 | + if (!xe_gt_is_media_type(gt)) { | |
| 112 | + xe_mmio_write32(gt, SCRATCH1LPFC, EN_L3_RW_CCS_CACHE_FLUSH); | |
| 113 | + reg = xe_mmio_read32(gt, XE2_GAMREQSTRM_CTRL); | |
| 114 | + reg |= CG_DIS_CNTLBUS; | |
| 115 | + xe_mmio_write32(gt, XE2_GAMREQSTRM_CTRL, reg); | |
| 116 | + } | |
| 117 | + | |
| 118 | + xe_gt_mcr_multicast_write(gt, XEHPC_L3CLOS_MASK(3), 0x3); | |
| 119 | + xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); | |
| 120 | +} | |
| 121 | + | |
| 122 | +static void xe_gt_disable_host_l2_vram(struct xe_gt *gt) | |
| 123 | +{ | |
| 124 | + u32 reg; | |
| 125 | + int err; | |
| 126 | + | |
| 127 | + if (!XE_WA(gt, 16023588340)) | |
| 128 | + return; | |
| 129 | + | |
| 130 | + if (xe_gt_is_media_type(gt)) | |
| 131 | + return; | |
| 132 | + | |
| 133 | + err = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | |
| 134 | + if (WARN_ON(err)) | |
| 135 | + return; | |
| 136 | + | |
| 137 | + reg = xe_mmio_read32(gt, XE2_GAMREQSTRM_CTRL); | |
| 138 | + reg &= ~CG_DIS_CNTLBUS; | |
| 139 | + xe_mmio_write32(gt, XE2_GAMREQSTRM_CTRL, reg); | |
| 140 | + | |
| 141 | + xe_force_wake_put(gt_to_fw(gt), XE_FW_GT); | |
| 142 | +} | |
| 143 | + | |
| 98 | 144 | /** |
| 99 | 145 | * xe_gt_remove() - Clean up the GT structures before driver removal |
| 100 | 146 | * @gt: the GT object |
| @@ -111,6 +157,8 @@ void xe_gt_remove(struct xe_gt *gt) · 10 unmodified lines | ||
| 111 | 157 | |
| 112 | 158 | for (i = 0; i < XE_ENGINE_CLASS_MAX; ++i) |
| 113 | 159 | xe_hw_fence_irq_finish(>->fence_irq[i]); |
| 160 | + | |
| 161 | + xe_gt_disable_host_l2_vram(gt); | |
| 114 | 162 | } |
| 115 | 163 | |
| 116 | 164 | static void gt_reset_worker(struct work_struct *w); |
| @@ -339,6 +387,7 @@ int xe_gt_init_early(struct xe_gt *gt) · 222 unmodified lines | ||
| 339 | 387 | |
| 340 | 388 | xe_force_wake_init_gt(gt, gt_to_fw(gt)); |
| 341 | 389 | xe_pcode_init(gt); |
| 390 | + spin_lock_init(>->global_invl_lock); | |
| 342 | 391 | |
| 343 | 392 | return 0; |
| 344 | 393 | } |
| @@ -508,6 +557,7 @@ int xe_gt_init_hwconfig(struct xe_gt *gt) · 163 unmodified lines | ||
| 508 | 557 | |
| 509 | 558 | xe_gt_mcr_init_early(gt); |
| 510 | 559 | xe_pat_init(gt); |
| 560 | + xe_gt_enable_host_l2_vram(gt); | |
| 511 | 561 | |
| 512 | 562 | err = xe_uc_init(>->uc); |
| 513 | 563 | if (err) |
| @@ -643,6 +693,8 @@ static int do_gt_restart(struct xe_gt *gt) · 129 unmodified lines | ||
| 643 | 693 | |
| 644 | 694 | xe_pat_init(gt); |
| 645 | 695 | |
| 696 | + xe_gt_enable_host_l2_vram(gt); | |
| 697 | + | |
| 646 | 698 | xe_gt_mcr_set_implicit_defaults(gt); |
| 647 | 699 | xe_reg_sr_apply_mmio(>->reg_sr, gt); |
| 648 | 700 | |
| @@ -796,6 +848,8 @@ int xe_gt_suspend(struct xe_gt *gt) · 147 unmodified lines | ||
| 796 | 848 | |
| 797 | 849 | xe_gt_idle_disable_pg(gt); |
| 798 | 850 | |
| 851 | + xe_gt_disable_host_l2_vram(gt); | |
| 852 | + | |
| 799 | 853 | XE_WARN_ON(xe_force_wake_put(gt_to_fw(gt), XE_FORCEWAKE_ALL)); |
| 800 | 854 | xe_gt_dbg(gt, "suspended\n"); |
| 801 | 855 | |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | #include <drm/drm_managed.h> |
| 7 | 7 | |
| 8 | −#include "regs/xe_sriov_regs.h" | |
| 8 | +#include "regs/xe_regs.h" | |
| 9 | 9 | |
| 10 | 10 | #include "xe_gt_sriov_pf.h" |
| 11 | 11 | #include "xe_gt_sriov_pf_config.h" |
| @@ -1401,6 +1401,7 @@ static int pf_provision_vf_lmem(struct xe_gt *gt, unsigned int vfid, u64 size) · 1400 unmodified lines | ||
| 1401 | 1401 | ALIGN(size, PAGE_SIZE), |
| 1402 | 1402 | ttm_bo_type_kernel, |
| 1403 | 1403 | XE_BO_FLAG_VRAM_IF_DGFX(tile) | |
| 1404 | + XE_BO_FLAG_NEEDS_2M | | |
| 1404 | 1405 | XE_BO_FLAG_PINNED); |
| 1405 | 1406 | if (IS_ERR(bo)) |
| 1406 | 1407 | return PTR_ERR(bo); |
| @@ -850,7 +850,7 @@ static struct vf_runtime_reg *vf_lookup_reg(struct xe_gt *gt, u32 addr) · 849 unmodified lines | ||
| 850 | 850 | |
| 851 | 851 | xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt))); |
| 852 | 852 | |
| 853 | − return bsearch(&key, runtime->regs, runtime->regs_size, sizeof(key), | |
| 853 | + return bsearch(&key, runtime->regs, runtime->num_regs, sizeof(key), | |
| 854 | 854 | vf_runtime_reg_cmp); |
| 855 | 855 | } |
| 856 | 856 | |
| @@ -892,6 +892,32 @@ u32 xe_gt_sriov_vf_read32(struct xe_gt *gt, struct xe_reg reg) · 35 unmodified lines | ||
| 892 | 892 | return rr->value; |
| 893 | 893 | } |
| 894 | 894 | |
| 895 | +/** | |
| 896 | + * xe_gt_sriov_vf_write32 - Handle a write to an inaccessible register. | |
| 897 | + * @gt: the &xe_gt | |
| 898 | + * @reg: the register to write | |
| 899 | + * @val: value to write | |
| 900 | + * | |
| 901 | + * This function is for VF use only. | |
| 902 | + * Currently it will trigger a WARN if running on debug build. | |
| 903 | + */ | |
| 904 | +void xe_gt_sriov_vf_write32(struct xe_gt *gt, struct xe_reg reg, u32 val) | |
| 905 | +{ | |
| 906 | + u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); | |
| 907 | + | |
| 908 | + xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt))); | |
| 909 | + xe_gt_assert(gt, !reg.vf); | |
| 910 | + | |
| 911 | + /* | |
| 912 | + * In the future, we may want to handle selected writes to inaccessible | |
| 913 | + * registers in some custom way, but for now let's just log a warning | |
| 914 | + * about such attempt, as likely we might be doing something wrong. | |
| 915 | + */ | |
| 916 | + xe_gt_WARN(gt, IS_ENABLED(CONFIG_DRM_XE_DEBUG), | |
| 917 | + "VF is trying to write %#x to an inaccessible register %#x+%#x\n", | |
| 918 | + val, reg.addr, addr - reg.addr); | |
| 919 | +} | |
| 920 | + | |
| 895 | 921 | /** |
| 896 | 922 | * xe_gt_sriov_vf_print_config - Print VF self config. |
| 897 | 923 | * @gt: the &xe_gt |
| @@ -22,6 +22,7 @@ u32 xe_gt_sriov_vf_gmdid(struct xe_gt *gt); · 21 unmodified lines | ||
| 22 | 22 | u16 xe_gt_sriov_vf_guc_ids(struct xe_gt *gt); |
| 23 | 23 | u64 xe_gt_sriov_vf_lmem(struct xe_gt *gt); |
| 24 | 24 | u32 xe_gt_sriov_vf_read32(struct xe_gt *gt, struct xe_reg reg); |
| 25 | +void xe_gt_sriov_vf_write32(struct xe_gt *gt, struct xe_reg reg, u32 val); | |
| 25 | 26 | |
| 26 | 27 | void xe_gt_sriov_vf_print_config(struct xe_gt *gt, struct drm_printer *p); |
| 27 | 28 | void xe_gt_sriov_vf_print_runtime(struct xe_gt *gt, struct drm_printer *p); |
| @@ -13,10 +13,13 @@ · 12 unmodified lines | ||
| 13 | 13 | #include "xe_guc.h" |
| 14 | 14 | #include "xe_guc_ct.h" |
| 15 | 15 | #include "xe_mmio.h" |
| 16 | +#include "xe_pm.h" | |
| 16 | 17 | #include "xe_sriov.h" |
| 17 | 18 | #include "xe_trace.h" |
| 18 | 19 | #include "regs/xe_guc_regs.h" |
| 19 | 20 | |
| 21 | +#define FENCE_STACK_BIT DMA_FENCE_FLAG_USER_BITS | |
| 22 | + | |
| 20 | 23 | /* |
| 21 | 24 | * TLB inval depends on pending commands in the CT queue and then the real |
| 22 | 25 | * invalidation time. Double up the time to process full CT queue |
| @@ -33,6 +36,24 @@ static long tlb_timeout_jiffies(struct xe_gt *gt) · 10 unmodified lines | ||
| 33 | 36 | return hw_tlb_timeout + 2 * delay; |
| 34 | 37 | } |
| 35 | 38 | |
| 39 | +static void | |
| 40 | +__invalidation_fence_signal(struct xe_device *xe, struct xe_gt_tlb_invalidation_fence *fence) | |
| 41 | +{ | |
| 42 | + bool stack = test_bit(FENCE_STACK_BIT, &fence->base.flags); | |
| 43 | + | |
| 44 | + trace_xe_gt_tlb_invalidation_fence_signal(xe, fence); | |
| 45 | + xe_gt_tlb_invalidation_fence_fini(fence); | |
| 46 | + dma_fence_signal(&fence->base); | |
| 47 | + if (!stack) | |
| 48 | + dma_fence_put(&fence->base); | |
| 49 | +} | |
| 50 | + | |
| 51 | +static void | |
| 52 | +invalidation_fence_signal(struct xe_device *xe, struct xe_gt_tlb_invalidation_fence *fence) | |
| 53 | +{ | |
| 54 | + list_del(&fence->link); | |
| 55 | + __invalidation_fence_signal(xe, fence); | |
| 56 | +} | |
| 36 | 57 | |
| 37 | 58 | static void xe_gt_tlb_fence_timeout(struct work_struct *work) |
| 38 | 59 | { |
| @@ -54,10 +75,8 @@ static void xe_gt_tlb_fence_timeout(struct work_struct *work) · 15 unmodified lines | ||
| 54 | 75 | xe_gt_err(gt, "TLB invalidation fence timeout, seqno=%d recv=%d", |
| 55 | 76 | fence->seqno, gt->tlb_invalidation.seqno_recv); |
| 56 | 77 | |
| 57 | − list_del(&fence->link); | |
| 58 | 78 | fence->base.error = -ETIME; |
| 59 | − dma_fence_signal(&fence->base); | |
| 60 | − dma_fence_put(&fence->base); | |
| 79 | + invalidation_fence_signal(xe, fence); | |
| 61 | 80 | } |
| 62 | 81 | if (!list_empty(>->tlb_invalidation.pending_fences)) |
| 63 | 82 | queue_delayed_work(system_wq, |
| @@ -87,21 +106,6 @@ int xe_gt_tlb_invalidation_init(struct xe_gt *gt) · 23 unmodified lines | ||
| 87 | 106 | return 0; |
| 88 | 107 | } |
| 89 | 108 | |
| 90 | −static void | |
| 91 | −__invalidation_fence_signal(struct xe_device *xe, struct xe_gt_tlb_invalidation_fence *fence) | |
| 92 | −{ | |
| 93 | − trace_xe_gt_tlb_invalidation_fence_signal(xe, fence); | |
| 94 | − dma_fence_signal(&fence->base); | |
| 95 | − dma_fence_put(&fence->base); | |
| 96 | −} | |
| 97 | − | |
| 98 | −static void | |
| 99 | −invalidation_fence_signal(struct xe_device *xe, struct xe_gt_tlb_invalidation_fence *fence) | |
| 100 | −{ | |
| 101 | − list_del(&fence->link); | |
| 102 | − __invalidation_fence_signal(xe, fence); | |
| 103 | −} | |
| 104 | − | |
| 105 | 109 | /** |
| 106 | 110 | * xe_gt_tlb_invalidation_reset - Initialize GT TLB invalidation reset |
| 107 | 111 | * @gt: graphics tile |
| @@ -111,7 +115,6 @@ invalidation_fence_signal(struct xe_device *xe, struct xe_gt_tlb_invalidation_fe · 3 unmodified lines | ||
| 111 | 115 | void xe_gt_tlb_invalidation_reset(struct xe_gt *gt) |
| 112 | 116 | { |
| 113 | 117 | struct xe_gt_tlb_invalidation_fence *fence, *next; |
| 114 | − struct xe_guc *guc = >->uc.guc; | |
| 115 | 118 | int pending_seqno; |
| 116 | 119 | |
| 117 | 120 | /* |
| @@ -134,7 +137,6 @@ void xe_gt_tlb_invalidation_reset(struct xe_gt *gt) · 16 unmodified lines | ||
| 134 | 137 | else |
| 135 | 138 | pending_seqno = gt->tlb_invalidation.seqno - 1; |
| 136 | 139 | WRITE_ONCE(gt->tlb_invalidation.seqno_recv, pending_seqno); |
| 137 | − wake_up_all(&guc->ct.wq); | |
| 138 | 140 | |
| 139 | 141 | list_for_each_entry_safe(fence, next, |
| 140 | 142 | >->tlb_invalidation.pending_fences, link) |
| @@ -165,6 +167,8 @@ static int send_tlb_invalidation(struct xe_guc *guc, · 24 unmodified lines | ||
| 165 | 167 | int seqno; |
| 166 | 168 | int ret; |
| 167 | 169 | |
| 170 | + xe_gt_assert(gt, fence); | |
| 171 | + | |
| 168 | 172 | /* |
| 169 | 173 | * XXX: The seqno algorithm relies on TLB invalidation being processed |
| 170 | 174 | * in order which they currently are, if that changes the algorithm will |
| @@ -173,14 +177,12 @@ static int send_tlb_invalidation(struct xe_guc *guc, · 2 unmodified lines | ||
| 173 | 177 | |
| 174 | 178 | mutex_lock(&guc->ct.lock); |
| 175 | 179 | seqno = gt->tlb_invalidation.seqno; |
| 176 | − if (fence) { | |
| 177 | − fence->seqno = seqno; | |
| 178 | − trace_xe_gt_tlb_invalidation_fence_send(xe, fence); | |
| 179 | − } | |
| 180 | + fence->seqno = seqno; | |
| 181 | + trace_xe_gt_tlb_invalidation_fence_send(xe, fence); | |
| 180 | 182 | action[1] = seqno; |
| 181 | 183 | ret = xe_guc_ct_send_locked(&guc->ct, action, len, |
| 182 | 184 | G2H_LEN_DW_TLB_INVALIDATE, 1); |
| 183 | − if (!ret && fence) { | |
| 185 | + if (!ret) { | |
| 184 | 186 | spin_lock_irq(>->tlb_invalidation.pending_lock); |
| 185 | 187 | /* |
| 186 | 188 | * We haven't actually published the TLB fence as per |
| @@ -201,7 +203,7 @@ static int send_tlb_invalidation(struct xe_guc *guc, · 14 unmodified lines | ||
| 201 | 203 | tlb_timeout_jiffies(gt)); |
| 202 | 204 | } |
| 203 | 205 | spin_unlock_irq(>->tlb_invalidation.pending_lock); |
| 204 | − } else if (ret < 0 && fence) { | |
| 206 | + } else if (ret < 0) { | |
| 205 | 207 | __invalidation_fence_signal(xe, fence); |
| 206 | 208 | } |
| 207 | 209 | if (!ret) { |
| @@ -209,7 +211,6 @@ static int send_tlb_invalidation(struct xe_guc *guc, · 1 unmodified line | ||
| 209 | 211 | TLB_INVALIDATION_SEQNO_MAX; |
| 210 | 212 | if (!gt->tlb_invalidation.seqno) |
| 211 | 213 | gt->tlb_invalidation.seqno = 1; |
| 212 | − ret = seqno; | |
| 213 | 214 | } |
| 214 | 215 | mutex_unlock(&guc->ct.lock); |
| 215 | 216 | |
| @@ -223,14 +224,16 @@ static int send_tlb_invalidation(struct xe_guc *guc, · 7 unmodified lines | ||
| 223 | 224 | /** |
| 224 | 225 | * xe_gt_tlb_invalidation_guc - Issue a TLB invalidation on this GT for the GuC |
| 225 | 226 | * @gt: graphics tile |
| 227 | + * @fence: invalidation fence which will be signal on TLB invalidation | |
| 228 | + * completion | |
| 226 | 229 | * |
| 227 | 230 | * Issue a TLB invalidation for the GuC. Completion of TLB is asynchronous and |
| 228 | − * caller can use seqno + xe_gt_tlb_invalidation_wait to wait for completion. | |
| 231 | + * caller can use the invalidation fence to wait for completion. | |
| 229 | 232 | * |
| 230 | − * Return: Seqno which can be passed to xe_gt_tlb_invalidation_wait on success, | |
| 231 | − * negative error code on error. | |
| 233 | + * Return: 0 on success, negative error code on error | |
| 232 | 234 | */ |
| 233 | −static int xe_gt_tlb_invalidation_guc(struct xe_gt *gt) | |
| 235 | +static int xe_gt_tlb_invalidation_guc(struct xe_gt *gt, | |
| 236 | + struct xe_gt_tlb_invalidation_fence *fence) | |
| 234 | 237 | { |
| 235 | 238 | u32 action[] = { |
| 236 | 239 | XE_GUC_ACTION_TLB_INVALIDATION, |
| @@ -238,7 +241,7 @@ static int xe_gt_tlb_invalidation_guc(struct xe_gt *gt) · 1 unmodified line | ||
| 238 | 241 | MAKE_INVAL_OP(XE_GUC_TLB_INVAL_GUC), |
| 239 | 242 | }; |
| 240 | 243 | |
| 241 | − return send_tlb_invalidation(>->uc.guc, NULL, action, | |
| 244 | + return send_tlb_invalidation(>->uc.guc, fence, action, | |
| 242 | 245 | ARRAY_SIZE(action)); |
| 243 | 246 | } |
| 244 | 247 | |
| @@ -257,13 +260,17 @@ int xe_gt_tlb_invalidation_ggtt(struct xe_gt *gt) · 12 unmodified lines | ||
| 257 | 260 | |
| 258 | 261 | if (xe_guc_ct_enabled(>->uc.guc.ct) && |
| 259 | 262 | gt->uc.guc.submission_state.enabled) { |
| 260 | − int seqno; | |
| 261 | − | |
| 262 | − seqno = xe_gt_tlb_invalidation_guc(gt); | |
| 263 | − if (seqno <= 0) | |
| 264 | − return seqno; | |
| 263 | + struct xe_gt_tlb_invalidation_fence fence; | |
| 264 | + int ret; | |
| 265 | + | |
| 266 | + xe_gt_tlb_invalidation_fence_init(gt, &fence, true); | |
| 267 | + ret = xe_gt_tlb_invalidation_guc(gt, &fence); | |
| 268 | + if (ret < 0) { | |
| 269 | + xe_gt_tlb_invalidation_fence_fini(&fence); | |
| 270 | + return ret; | |
| 271 | + } | |
| 265 | 272 | |
| 266 | − xe_gt_tlb_invalidation_wait(gt, seqno); | |
| 273 | + xe_gt_tlb_invalidation_fence_wait(&fence); | |
| 267 | 274 | } else if (xe_device_uc_enabled(xe) && !xe_device_wedged(xe)) { |
| 268 | 275 | if (IS_SRIOV_VF(xe)) |
| 269 | 276 | return 0; |
| @@ -290,18 +297,16 @@ int xe_gt_tlb_invalidation_ggtt(struct xe_gt *gt) · 20 unmodified lines | ||
| 290 | 297 | * |
| 291 | 298 | * @gt: graphics tile |
| 292 | 299 | * @fence: invalidation fence which will be signal on TLB invalidation |
| 293 | − * completion, can be NULL | |
| 300 | + * completion | |
| 294 | 301 | * @start: start address |
| 295 | 302 | * @end: end address |
| 296 | 303 | * @asid: address space id |
| 297 | 304 | * |
| 298 | 305 | * Issue a range based TLB invalidation if supported, if not fallback to a full |
| 299 | − * TLB invalidation. Completion of TLB is asynchronous and caller can either use | |
| 300 | − * the invalidation fence or seqno + xe_gt_tlb_invalidation_wait to wait for | |
| 301 | − * completion. | |
| 306 | + * TLB invalidation. Completion of TLB is asynchronous and caller can use | |
| 307 | + * the invalidation fence to wait for completion. | |
| 302 | 308 | * |
| 303 | − * Return: Seqno which can be passed to xe_gt_tlb_invalidation_wait on success, | |
| 304 | − * negative error code on error. | |
| 309 | + * Return: Negative error code on error, 0 on success | |
| 305 | 310 | */ |
| 306 | 311 | int xe_gt_tlb_invalidation_range(struct xe_gt *gt, |
| 307 | 312 | struct xe_gt_tlb_invalidation_fence *fence, |
| @@ -312,11 +317,11 @@ int xe_gt_tlb_invalidation_range(struct xe_gt *gt, · 4 unmodified lines | ||
| 312 | 317 | u32 action[MAX_TLB_INVALIDATION_LEN]; |
| 313 | 318 | int len = 0; |
| 314 | 319 | |
| 320 | + xe_gt_assert(gt, fence); | |
| 321 | + | |
| 315 | 322 | /* Execlists not supported */ |
| 316 | 323 | if (gt_to_xe(gt)->info.force_execlist) { |
| 317 | − if (fence) | |
| 318 | − __invalidation_fence_signal(xe, fence); | |
| 319 | − | |
| 324 | + __invalidation_fence_signal(xe, fence); | |
| 320 | 325 | return 0; |
| 321 | 326 | } |
| 322 | 327 | |
| @@ -382,12 +387,10 @@ int xe_gt_tlb_invalidation_range(struct xe_gt *gt, · 59 unmodified lines | ||
| 382 | 387 | * @vma: VMA to invalidate |
| 383 | 388 | * |
| 384 | 389 | * Issue a range based TLB invalidation if supported, if not fallback to a full |
| 385 | − * TLB invalidation. Completion of TLB is asynchronous and caller can either use | |
| 386 | − * the invalidation fence or seqno + xe_gt_tlb_invalidation_wait to wait for | |
| 387 | − * completion. | |
| 390 | + * TLB invalidation. Completion of TLB is asynchronous and caller can use | |
| 391 | + * the invalidation fence to wait for completion. | |
| 388 | 392 | * |
| 389 | − * Return: Seqno which can be passed to xe_gt_tlb_invalidation_wait on success, | |
| 390 | − * negative error code on error. | |
| 393 | + * Return: Negative error code on error, 0 on success | |
| 391 | 394 | */ |
| 392 | 395 | int xe_gt_tlb_invalidation_vma(struct xe_gt *gt, |
| 393 | 396 | struct xe_gt_tlb_invalidation_fence *fence, |
| @@ -400,43 +403,6 @@ int xe_gt_tlb_invalidation_vma(struct xe_gt *gt, · 6 unmodified lines | ||
| 400 | 403 | xe_vma_vm(vma)->usm.asid); |
| 401 | 404 | } |
| 402 | 405 | |
| 403 | −/** | |
| 404 | − * xe_gt_tlb_invalidation_wait - Wait for TLB to complete | |
| 405 | − * @gt: graphics tile | |
| 406 | − * @seqno: seqno to wait which was returned from xe_gt_tlb_invalidation | |
| 407 | − * | |
| 408 | − * Wait for tlb_timeout_jiffies() for a TLB invalidation to complete. | |
| 409 | − * | |
| 410 | − * Return: 0 on success, -ETIME on TLB invalidation timeout | |
| 411 | − */ | |
| 412 | −int xe_gt_tlb_invalidation_wait(struct xe_gt *gt, int seqno) | |
| 413 | −{ | |
| 414 | − struct xe_guc *guc = >->uc.guc; | |
| 415 | − int ret; | |
| 416 | − | |
| 417 | − /* Execlists not supported */ | |
| 418 | − if (gt_to_xe(gt)->info.force_execlist) | |
| 419 | − return 0; | |
| 420 | − | |
| 421 | − /* | |
| 422 | − * XXX: See above, this algorithm only works if seqno are always in | |
| 423 | − * order | |
| 424 | − */ | |
| 425 | − ret = wait_event_timeout(guc->ct.wq, | |
| 426 | − tlb_invalidation_seqno_past(gt, seqno), | |
| 427 | − tlb_timeout_jiffies(gt)); | |
| 428 | − if (!ret) { | |
| 429 | − struct drm_printer p = xe_gt_err_printer(gt); | |
| 430 | − | |
| 431 | − xe_gt_err(gt, "TLB invalidation time'd out, seqno=%d, recv=%d\n", | |
| 432 | − seqno, gt->tlb_invalidation.seqno_recv); | |
| 433 | − xe_guc_ct_print(&guc->ct, &p, true); | |
| 434 | − return -ETIME; | |
| 435 | − } | |
| 436 | − | |
| 437 | − return 0; | |
| 438 | −} | |
| 439 | − | |
| 440 | 406 | /** |
| 441 | 407 | * xe_guc_tlb_invalidation_done_handler - TLB invalidation done handler |
| 442 | 408 | * @guc: guc |
| @@ -480,12 +446,7 @@ int xe_guc_tlb_invalidation_done_handler(struct xe_guc *guc, u32 *msg, u32 len) · 37 unmodified lines | ||
| 480 | 446 | return 0; |
| 481 | 447 | } |
| 482 | 448 | |
| 483 | − /* | |
| 484 | − * wake_up_all() and wait_event_timeout() already have the correct | |
| 485 | − * barriers. | |
| 486 | − */ | |
| 487 | 449 | WRITE_ONCE(gt->tlb_invalidation.seqno_recv, msg[0]); |
| 488 | − wake_up_all(&guc->ct.wq); | |
| 489 | 450 | |
| 490 | 451 | list_for_each_entry_safe(fence, next, |
| 491 | 452 | >->tlb_invalidation.pending_fences, link) { |
| @@ -508,3 +469,59 @@ int xe_guc_tlb_invalidation_done_handler(struct xe_guc *guc, u32 *msg, u32 len) · 16 unmodified lines | ||
| 508 | 469 | |
| 509 | 470 | return 0; |
| 510 | 471 | } |
| 472 | + | |
| 473 | +static const char * | |
| 474 | +invalidation_fence_get_driver_name(struct dma_fence *dma_fence) | |
| 475 | +{ | |
| 476 | + return "xe"; | |
| 477 | +} | |
| 478 | + | |
| 479 | +static const char * | |
| 480 | +invalidation_fence_get_timeline_name(struct dma_fence *dma_fence) | |
| 481 | +{ | |
| 482 | + return "invalidation_fence"; | |
| 483 | +} | |
| 484 | + | |
| 485 | +static const struct dma_fence_ops invalidation_fence_ops = { | |
| 486 | + .get_driver_name = invalidation_fence_get_driver_name, | |
| 487 | + .get_timeline_name = invalidation_fence_get_timeline_name, | |
| 488 | +}; | |
| 489 | + | |
| 490 | +/** | |
| 491 | + * xe_gt_tlb_invalidation_fence_init - Initialize TLB invalidation fence | |
| 492 | + * @gt: GT | |
| 493 | + * @fence: TLB invalidation fence to initialize | |
| 494 | + * @stack: fence is stack variable | |
| 495 | + * | |
| 496 | + * Initialize TLB invalidation fence for use. xe_gt_tlb_invalidation_fence_fini | |
| 497 | + * must be called if fence is not signaled. | |
| 498 | + */ | |
| 499 | +void xe_gt_tlb_invalidation_fence_init(struct xe_gt *gt, | |
| 500 | + struct xe_gt_tlb_invalidation_fence *fence, | |
| 501 | + bool stack) | |
| 502 | +{ | |
| 503 | + xe_pm_runtime_get_noresume(gt_to_xe(gt)); | |
| 504 | + | |
| 505 | + spin_lock_irq(>->tlb_invalidation.lock); | |
| 506 | + dma_fence_init(&fence->base, &invalidation_fence_ops, | |
| 507 | + >->tlb_invalidation.lock, | |
| 508 | + dma_fence_context_alloc(1), 1); | |
| 509 | + spin_unlock_irq(>->tlb_invalidation.lock); | |
| 510 | + INIT_LIST_HEAD(&fence->link); | |
| 511 | + if (stack) | |
| 512 | + set_bit(FENCE_STACK_BIT, &fence->base.flags); | |
| 513 | + else | |
| 514 | + dma_fence_get(&fence->base); | |
| 515 | + fence->gt = gt; | |
| 516 | +} | |
| 517 | + | |
| 518 | +/** | |
| 519 | + * xe_gt_tlb_invalidation_fence_fini - Finalize TLB invalidation fence | |
| 520 | + * @fence: TLB invalidation fence to finalize | |
| 521 | + * | |
| 522 | + * Drop PM ref which fence took durinig init. | |
| 523 | + */ | |
| 524 | +void xe_gt_tlb_invalidation_fence_fini(struct xe_gt_tlb_invalidation_fence *fence) | |
| 525 | +{ | |
| 526 | + xe_pm_runtime_put(gt_to_xe(fence->gt)); | |
| 527 | +} | |
| @@ -23,7 +23,17 @@ int xe_gt_tlb_invalidation_vma(struct xe_gt *gt, · 22 unmodified lines | ||
| 23 | 23 | int xe_gt_tlb_invalidation_range(struct xe_gt *gt, |
| 24 | 24 | struct xe_gt_tlb_invalidation_fence *fence, |
| 25 | 25 | u64 start, u64 end, u32 asid); |
| 26 | −int xe_gt_tlb_invalidation_wait(struct xe_gt *gt, int seqno); | |
| 27 | 26 | int xe_guc_tlb_invalidation_done_handler(struct xe_guc *guc, u32 *msg, u32 len); |
| 28 | 27 | |
| 28 | +void xe_gt_tlb_invalidation_fence_init(struct xe_gt *gt, | |
| 29 | + struct xe_gt_tlb_invalidation_fence *fence, | |
| 30 | + bool stack); | |
| 31 | +void xe_gt_tlb_invalidation_fence_fini(struct xe_gt_tlb_invalidation_fence *fence); | |
| 32 | + | |
| 33 | +static inline void | |
| 34 | +xe_gt_tlb_invalidation_fence_wait(struct xe_gt_tlb_invalidation_fence *fence) | |
| 35 | +{ | |
| 36 | + dma_fence_wait(&fence->base, false); | |
| 37 | +} | |
| 38 | + | |
| 29 | 39 | #endif /* _XE_GT_TLB_INVALIDATION_ */ |
| @@ -8,6 +8,8 @@ · 7 unmodified lines | ||
| 8 | 8 | |
| 9 | 9 | #include <linux/dma-fence.h> |
| 10 | 10 | |
| 11 | +struct xe_gt; | |
| 12 | + | |
| 11 | 13 | /** |
| 12 | 14 | * struct xe_gt_tlb_invalidation_fence - XE GT TLB invalidation fence |
| 13 | 15 | * |
| @@ -17,6 +19,8 @@ · 3 unmodified lines | ||
| 17 | 19 | struct xe_gt_tlb_invalidation_fence { |
| 18 | 20 | /** @base: dma fence base */ |
| 19 | 21 | struct dma_fence base; |
| 22 | + /** @gt: GT which fence belong to */ | |
| 23 | + struct xe_gt *gt; | |
| 20 | 24 | /** @link: link into list of pending tlb fences */ |
| 21 | 25 | struct list_head link; |
| 22 | 26 | /** @seqno: seqno of TLB invalidation to signal fence one */ |
| @@ -6,6 +6,7 @@ · 5 unmodified lines | ||
| 6 | 6 | #include "xe_gt_topology.h" |
| 7 | 7 | |
| 8 | 8 | #include <linux/bitmap.h> |
| 9 | +#include <linux/compiler.h> | |
| 9 | 10 | |
| 10 | 11 | #include "regs/xe_gt_regs.h" |
| 11 | 12 | #include "xe_assert.h" |
| @@ -31,7 +32,7 @@ load_dss_mask(struct xe_gt *gt, xe_dss_mask_t mask, int numregs, ...) · 19 unmodified lines | ||
| 31 | 32 | } |
| 32 | 33 | |
| 33 | 34 | static void |
| 34 | −load_eu_mask(struct xe_gt *gt, xe_eu_mask_t mask) | |
| 35 | +load_eu_mask(struct xe_gt *gt, xe_eu_mask_t mask, enum xe_gt_eu_type *eu_type) | |
| 35 | 36 | { |
| 36 | 37 | struct xe_device *xe = gt_to_xe(gt); |
| 37 | 38 | u32 reg_val = xe_mmio_read32(gt, XELP_EU_ENABLE); |
| @@ -47,11 +48,13 @@ load_eu_mask(struct xe_gt *gt, xe_eu_mask_t mask) · 9 unmodified lines | ||
| 47 | 48 | if (GRAPHICS_VERx100(xe) < 1250) |
| 48 | 49 | reg_val = ~reg_val & XELP_EU_MASK; |
| 49 | 50 | |
| 50 | − /* On PVC, one bit = one EU */ | |
| 51 | − if (GRAPHICS_VERx100(xe) == 1260) { | |
| 51 | + if (GRAPHICS_VERx100(xe) == 1260 || GRAPHICS_VER(xe) >= 20) { | |
| 52 | + /* SIMD16 EUs, one bit == one EU */ | |
| 53 | + *eu_type = XE_GT_EU_TYPE_SIMD16; | |
| 52 | 54 | val = reg_val; |
| 53 | 55 | } else { |
| 54 | − /* All other platforms, one bit = 2 EU */ | |
| 56 | + /* SIMD8 EUs, one bit == 2 EU */ | |
| 57 | + *eu_type = XE_GT_EU_TYPE_SIMD8; | |
| 55 | 58 | for (i = 0; i < fls(reg_val); i++) |
| 56 | 59 | if (reg_val & BIT(i)) |
| 57 | 60 | val |= 0x3 << 2 * i; |
| @@ -213,7 +216,7 @@ xe_gt_topology_init(struct xe_gt *gt) · 155 unmodified lines | ||
| 213 | 216 | XEHP_GT_COMPUTE_DSS_ENABLE, |
| 214 | 217 | XEHPC_GT_COMPUTE_DSS_ENABLE_EXT, |
| 215 | 218 | XE2_GT_COMPUTE_DSS_2); |
| 216 | − load_eu_mask(gt, gt->fuse_topo.eu_mask_per_dss); | |
| 219 | + load_eu_mask(gt, gt->fuse_topo.eu_mask_per_dss, >->fuse_topo.eu_type); | |
| 217 | 220 | load_l3_bank_mask(gt, gt->fuse_topo.l3_bank_mask); |
| 218 | 221 | |
| 219 | 222 | p = drm_dbg_printer(>_to_xe(gt)->drm, DRM_UT_DRIVER, "GT topology"); |
| @@ -221,6 +224,18 @@ xe_gt_topology_init(struct xe_gt *gt) · 1 unmodified line | ||
| 221 | 224 | xe_gt_topology_dump(gt, &p); |
| 222 | 225 | } |
| 223 | 226 | |
| 227 | +static const char *eu_type_to_str(enum xe_gt_eu_type eu_type) | |
| 228 | +{ | |
| 229 | + switch (eu_type) { | |
| 230 | + case XE_GT_EU_TYPE_SIMD16: | |
| 231 | + return "simd16"; | |
| 232 | + case XE_GT_EU_TYPE_SIMD8: | |
| 233 | + return "simd8"; | |
| 234 | + } | |
| 235 | + | |
| 236 | + return NULL; | |
| 237 | +} | |
| 238 | + | |
| 224 | 239 | void |
| 225 | 240 | xe_gt_topology_dump(struct xe_gt *gt, struct drm_printer *p) |
| 226 | 241 | { |
| @@ -231,6 +246,8 @@ xe_gt_topology_dump(struct xe_gt *gt, struct drm_printer *p) · 4 unmodified lines | ||
| 231 | 246 | |
| 232 | 247 | drm_printf(p, "EU mask per DSS: %*pb\n", XE_MAX_EU_FUSE_BITS, |
| 233 | 248 | gt->fuse_topo.eu_mask_per_dss); |
| 249 | + drm_printf(p, "EU type: %s\n", | |
| 250 | + eu_type_to_str(gt->fuse_topo.eu_type)); | |
| 234 | 251 | |
| 235 | 252 | drm_printf(p, "L3 bank mask: %*pb\n", XE_MAX_L3_BANK_MASK_BITS, |
| 236 | 253 | gt->fuse_topo.l3_bank_mask); |
| @@ -27,6 +27,11 @@ enum xe_gt_type { · 26 unmodified lines | ||
| 27 | 27 | XE_GT_TYPE_MEDIA, |
| 28 | 28 | }; |
| 29 | 29 | |
| 30 | +enum xe_gt_eu_type { | |
| 31 | + XE_GT_EU_TYPE_SIMD8, | |
| 32 | + XE_GT_EU_TYPE_SIMD16, | |
| 33 | +}; | |
| 34 | + | |
| 30 | 35 | #define XE_MAX_DSS_FUSE_REGS 3 |
| 31 | 36 | #define XE_MAX_DSS_FUSE_BITS (32 * XE_MAX_DSS_FUSE_REGS) |
| 32 | 37 | #define XE_MAX_EU_FUSE_REGS 1 |
| @@ -343,6 +348,12 @@ struct xe_gt { · 310 unmodified lines | ||
| 343 | 348 | |
| 344 | 349 | /** @fuse_topo.l3_bank_mask: L3 bank mask */ |
| 345 | 350 | xe_l3_bank_mask_t l3_bank_mask; |
| 351 | + | |
| 352 | + /** | |
| 353 | + * @fuse_topo.eu_type: type/width of EU stored in | |
| 354 | + * fuse_topo.eu_mask_per_dss | |
| 355 | + */ | |
| 356 | + enum xe_gt_eu_type eu_type; | |
| 346 | 357 | } fuse_topo; |
| 347 | 358 | |
| 348 | 359 | /** @steering: register steering for individual HW units */ |
| @@ -362,6 +373,12 @@ struct xe_gt { · 13 unmodified lines | ||
| 362 | 373 | */ |
| 363 | 374 | spinlock_t mcr_lock; |
| 364 | 375 | |
| 376 | + /** | |
| 377 | + * @global_invl_lock: protects the register for the duration | |
| 378 | + * of a global invalidation of l2 cache | |
| 379 | + */ | |
| 380 | + spinlock_t global_invl_lock; | |
| 381 | + | |
| 365 | 382 | /** @wa_active: keep track of active workarounds */ |
| 366 | 383 | struct { |
| 367 | 384 | /** @wa_active.gt: bitmap with active GT workarounds */ |
| @@ -370,8 +387,14 @@ struct xe_gt { · 2 unmodified lines | ||
| 370 | 387 | unsigned long *engine; |
| 371 | 388 | /** @wa_active.lrc: bitmap with active LRC workarounds */ |
| 372 | 389 | unsigned long *lrc; |
| 373 | − /** @wa_active.oob: bitmap with active OOB workaroudns */ | |
| 390 | + /** @wa_active.oob: bitmap with active OOB workarounds */ | |
| 374 | 391 | unsigned long *oob; |
| 392 | + /** | |
| 393 | + * @wa_active.oob_initialized: mark oob as initialized to help | |
| 394 | + * detecting misuse of XE_WA() - it can only be called on | |
| 395 | + * initialization after OOB WAs have being processed | |
| 396 | + */ | |
| 397 | + bool oob_initialized; | |
| 375 | 398 | } wa_active; |
| 376 | 399 | |
| 377 | 400 | /** @user_engines: engines present in GT and available to userspace */ |
| @@ -327,6 +327,8 @@ static void xe_guc_ct_set_state(struct xe_guc_ct *ct, · 326 unmodified lines | ||
| 327 | 327 | xe_gt_assert(ct_to_gt(ct), ct->g2h_outstanding == 0 || |
| 328 | 328 | state == XE_GUC_CT_STATE_STOPPED); |
| 329 | 329 | |
| 330 | + if (ct->g2h_outstanding) | |
| 331 | + xe_pm_runtime_put(ct_to_xe(ct)); | |
| 330 | 332 | ct->g2h_outstanding = 0; |
| 331 | 333 | ct->state = state; |
| 332 | 334 | |
| @@ -495,10 +497,15 @@ static void h2g_reserve_space(struct xe_guc_ct *ct, u32 cmd_len) · 162 unmodified lines | ||
| 495 | 497 | static void __g2h_reserve_space(struct xe_guc_ct *ct, u32 g2h_len, u32 num_g2h) |
| 496 | 498 | { |
| 497 | 499 | xe_gt_assert(ct_to_gt(ct), g2h_len <= ct->ctbs.g2h.info.space); |
| 500 | + xe_gt_assert(ct_to_gt(ct), (!g2h_len && !num_g2h) || | |
| 501 | + (g2h_len && num_g2h)); | |
| 498 | 502 | |
| 499 | 503 | if (g2h_len) { |
| 500 | 504 | lockdep_assert_held(&ct->fast_lock); |
| 501 | 505 | |
| 506 | + if (!ct->g2h_outstanding) | |
| 507 | + xe_pm_runtime_get_noresume(ct_to_xe(ct)); | |
| 508 | + | |
| 502 | 509 | ct->ctbs.g2h.info.space -= g2h_len; |
| 503 | 510 | ct->g2h_outstanding += num_g2h; |
| 504 | 511 | } |
| @@ -509,9 +516,11 @@ static void __g2h_release_space(struct xe_guc_ct *ct, u32 g2h_len) · 4 unmodified lines | ||
| 509 | 516 | lockdep_assert_held(&ct->fast_lock); |
| 510 | 517 | xe_gt_assert(ct_to_gt(ct), ct->ctbs.g2h.info.space + g2h_len <= |
| 511 | 518 | ct->ctbs.g2h.info.size - ct->ctbs.g2h.info.resv_space); |
| 519 | + xe_gt_assert(ct_to_gt(ct), ct->g2h_outstanding); | |
| 512 | 520 | |
| 513 | 521 | ct->ctbs.g2h.info.space += g2h_len; |
| 514 | − --ct->g2h_outstanding; | |
| 522 | + if (!--ct->g2h_outstanding) | |
| 523 | + xe_pm_runtime_put(ct_to_xe(ct)); | |
| 515 | 524 | } |
| 516 | 525 | |
| 517 | 526 | static void g2h_release_space(struct xe_guc_ct *ct, u32 g2h_len) |
| @@ -97,8 +97,8 @@ int xe_guc_id_mgr_init(struct xe_guc_id_mgr *idm, unsigned int limit) · 96 unmodified lines | ||
| 97 | 97 | if (ret) |
| 98 | 98 | return ret; |
| 99 | 99 | |
| 100 | − xe_gt_info(idm_to_gt(idm), "using %u GUC ID%s\n", | |
| 101 | − idm->total, str_plural(idm->total)); | |
| 100 | + xe_gt_dbg(idm_to_gt(idm), "using %u GuC ID%s\n", | |
| 101 | + idm->total, str_plural(idm->total)); | |
| 102 | 102 | return 0; |
| 103 | 103 | } |
| 104 | 104 | |
| @@ -1071,7 +1071,9 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) · 1070 unmodified lines | ||
| 1071 | 1071 | struct xe_exec_queue *q = job->q; |
| 1072 | 1072 | struct xe_gpu_scheduler *sched = &q->guc->sched; |
| 1073 | 1073 | struct xe_guc *guc = exec_queue_to_guc(q); |
| 1074 | + const char *process_name = "no process"; | |
| 1074 | 1075 | int err = -ETIME; |
| 1076 | + pid_t pid = -1; | |
| 1075 | 1077 | int i = 0; |
| 1076 | 1078 | bool wedged, skip_timeout_check; |
| 1077 | 1079 | |
| @@ -1168,9 +1170,14 @@ trigger_reset: · 90 unmodified lines | ||
| 1168 | 1170 | goto sched_enable; |
| 1169 | 1171 | } |
| 1170 | 1172 | |
| 1171 | − xe_gt_notice(guc_to_gt(guc), "Timedout job: seqno=%u, lrc_seqno=%u, guc_id=%d, flags=0x%lx", | |
| 1173 | + if (q->vm && q->vm->xef) { | |
| 1174 | + process_name = q->vm->xef->process_name; | |
| 1175 | + pid = q->vm->xef->pid; | |
| 1176 | + } | |
| 1177 | + xe_gt_notice(guc_to_gt(guc), "Timedout job: seqno=%u, lrc_seqno=%u, guc_id=%d, flags=0x%lx in %s [%d]", | |
| 1172 | 1178 | xe_sched_job_seqno(job), xe_sched_job_lrc_seqno(job), |
| 1173 | − q->guc->id, q->flags); | |
| 1179 | + q->guc->id, q->flags, process_name, pid); | |
| 1180 | + | |
| 1174 | 1181 | trace_xe_sched_job_timedout(job); |
| 1175 | 1182 | |
| 1176 | 1183 | if (!exec_queue_killed(q)) |
| @@ -1312,6 +1319,15 @@ static void __guc_exec_queue_process_msg_set_sched_props(struct xe_sched_msg *ms · 135 unmodified lines | ||
| 1312 | 1319 | kfree(msg); |
| 1313 | 1320 | } |
| 1314 | 1321 | |
| 1322 | +static void __suspend_fence_signal(struct xe_exec_queue *q) | |
| 1323 | +{ | |
| 1324 | + if (!q->guc->suspend_pending) | |
| 1325 | + return; | |
| 1326 | + | |
| 1327 | + WRITE_ONCE(q->guc->suspend_pending, false); | |
| 1328 | + wake_up(&q->guc->suspend_wait); | |
| 1329 | +} | |
| 1330 | + | |
| 1315 | 1331 | static void suspend_fence_signal(struct xe_exec_queue *q) |
| 1316 | 1332 | { |
| 1317 | 1333 | struct xe_guc *guc = exec_queue_to_guc(q); |
| @@ -1321,9 +1337,7 @@ static void suspend_fence_signal(struct xe_exec_queue *q) · 3 unmodified lines | ||
| 1321 | 1337 | guc_read_stopped(guc)); |
| 1322 | 1338 | xe_assert(xe, q->guc->suspend_pending); |
| 1323 | 1339 | |
| 1324 | − q->guc->suspend_pending = false; | |
| 1325 | − smp_wmb(); | |
| 1326 | − wake_up(&q->guc->suspend_wait); | |
| 1340 | + __suspend_fence_signal(q); | |
| 1327 | 1341 | } |
| 1328 | 1342 | |
| 1329 | 1343 | static void __guc_exec_queue_process_msg_suspend(struct xe_sched_msg *msg) |
| @@ -1375,6 +1389,8 @@ static void __guc_exec_queue_process_msg_resume(struct xe_sched_msg *msg) · 45 unmodified lines | ||
| 1375 | 1389 | |
| 1376 | 1390 | static void guc_exec_queue_process_msg(struct xe_sched_msg *msg) |
| 1377 | 1391 | { |
| 1392 | + struct xe_device *xe = guc_to_xe(exec_queue_to_guc(msg->private_data)); | |
| 1393 | + | |
| 1378 | 1394 | trace_xe_sched_msg_recv(msg); |
| 1379 | 1395 | |
| 1380 | 1396 | switch (msg->opcode) { |
| @@ -1393,6 +1409,8 @@ static void guc_exec_queue_process_msg(struct xe_sched_msg *msg) · 12 unmodified lines | ||
| 1393 | 1409 | default: |
| 1394 | 1410 | XE_WARN_ON("Unknown message type"); |
| 1395 | 1411 | } |
| 1412 | + | |
| 1413 | + xe_pm_runtime_put(xe); | |
| 1396 | 1414 | } |
| 1397 | 1415 | |
| 1398 | 1416 | static const struct drm_sched_backend_ops drm_sched_ops = { |
| @@ -1476,12 +1494,15 @@ static void guc_exec_queue_kill(struct xe_exec_queue *q) · 77 unmodified lines | ||
| 1476 | 1494 | { |
| 1477 | 1495 | trace_xe_exec_queue_kill(q); |
| 1478 | 1496 | set_exec_queue_killed(q); |
| 1497 | + __suspend_fence_signal(q); | |
| 1479 | 1498 | xe_guc_exec_queue_trigger_cleanup(q); |
| 1480 | 1499 | } |
| 1481 | 1500 | |
| 1482 | 1501 | static void guc_exec_queue_add_msg(struct xe_exec_queue *q, struct xe_sched_msg *msg, |
| 1483 | 1502 | u32 opcode) |
| 1484 | 1503 | { |
| 1504 | + xe_pm_runtime_get_noresume(guc_to_xe(exec_queue_to_guc(q))); | |
| 1505 | + | |
| 1485 | 1506 | INIT_LIST_HEAD(&msg->link); |
| 1486 | 1507 | msg->opcode = opcode; |
| 1487 | 1508 | msg->private_data = q; |
| @@ -1572,12 +1593,31 @@ static int guc_exec_queue_suspend(struct xe_exec_queue *q) · 84 unmodified lines | ||
| 1572 | 1593 | return 0; |
| 1573 | 1594 | } |
| 1574 | 1595 | |
| 1575 | −static void guc_exec_queue_suspend_wait(struct xe_exec_queue *q) | |
| 1596 | +static int guc_exec_queue_suspend_wait(struct xe_exec_queue *q) | |
| 1576 | 1597 | { |
| 1577 | 1598 | struct xe_guc *guc = exec_queue_to_guc(q); |
| 1599 | + int ret; | |
| 1600 | + | |
| 1601 | + /* | |
| 1602 | + * Likely don't need to check exec_queue_killed() as we clear | |
| 1603 | + * suspend_pending upon kill but to be paranoid but races in which | |
| 1604 | + * suspend_pending is set after kill also check kill here. | |
| 1605 | + */ | |
| 1606 | + ret = wait_event_timeout(q->guc->suspend_wait, | |
| 1607 | + !READ_ONCE(q->guc->suspend_pending) || | |
| 1608 | + exec_queue_killed(q) || | |
| 1609 | + guc_read_stopped(guc), | |
| 1610 | + HZ * 5); | |
| 1578 | 1611 | |
| 1579 | − wait_event(q->guc->suspend_wait, !q->guc->suspend_pending || | |
| 1580 | − guc_read_stopped(guc)); | |
| 1612 | + if (!ret) { | |
| 1613 | + xe_gt_warn(guc_to_gt(guc), | |
| 1614 | + "Suspend fence, guc_id=%d, failed to respond", | |
| 1615 | + q->guc->id); | |
| 1616 | + /* XXX: Trigger GT reset? */ | |
| 1617 | + return -ETIME; | |
| 1618 | + } | |
| 1619 | + | |
| 1620 | + return 0; | |
| 1581 | 1621 | } |
| 1582 | 1622 | |
| 1583 | 1623 | static void guc_exec_queue_resume(struct xe_exec_queue *q) |
| @@ -92,7 +92,7 @@ void xe_heci_gsc_fini(struct xe_device *xe) · 91 unmodified lines | ||
| 92 | 92 | { |
| 93 | 93 | struct xe_heci_gsc *heci_gsc = &xe->heci_gsc; |
| 94 | 94 | |
| 95 | − if (!HAS_HECI_GSCFI(xe)) | |
| 95 | + if (!HAS_HECI_GSCFI(xe) && !HAS_HECI_CSCFI(xe)) | |
| 96 | 96 | return; |
| 97 | 97 | |
| 98 | 98 | if (heci_gsc->adev) { |
| @@ -177,12 +177,14 @@ void xe_heci_gsc_init(struct xe_device *xe) · 78 unmodified lines | ||
| 177 | 177 | const struct heci_gsc_def *def; |
| 178 | 178 | int ret; |
| 179 | 179 | |
| 180 | − if (!HAS_HECI_GSCFI(xe)) | |
| 180 | + if (!HAS_HECI_GSCFI(xe) && !HAS_HECI_CSCFI(xe)) | |
| 181 | 181 | return; |
| 182 | 182 | |
| 183 | 183 | heci_gsc->irq = -1; |
| 184 | 184 | |
| 185 | − if (xe->info.platform == XE_PVC) { | |
| 185 | + if (xe->info.platform == XE_BATTLEMAGE) { | |
| 186 | + def = &heci_gsc_def_dg2; | |
| 187 | + } else if (xe->info.platform == XE_PVC) { | |
| 186 | 188 | def = &heci_gsc_def_pvc; |
| 187 | 189 | } else if (xe->info.platform == XE_DG2) { |
| 188 | 190 | def = &heci_gsc_def_dg2; |
| @@ -232,3 +234,23 @@ void xe_heci_gsc_irq_handler(struct xe_device *xe, u32 iir) · 43 unmodified lines | ||
| 232 | 234 | if (ret) |
| 233 | 235 | drm_err_ratelimited(&xe->drm, "error handling GSC irq: %d\n", ret); |
| 234 | 236 | } |
| 237 | + | |
| 238 | +void xe_heci_csc_irq_handler(struct xe_device *xe, u32 iir) | |
| 239 | +{ | |
| 240 | + int ret; | |
| 241 | + | |
| 242 | + if ((iir & CSC_IRQ_INTF(1)) == 0) | |
| 243 | + return; | |
| 244 | + | |
| 245 | + if (!HAS_HECI_CSCFI(xe)) { | |
| 246 | + drm_warn_once(&xe->drm, "CSC irq: not supported"); | |
| 247 | + return; | |
| 248 | + } | |
| 249 | + | |
| 250 | + if (xe->heci_gsc.irq < 0) | |
| 251 | + return; | |
| 252 | + | |
| 253 | + ret = generic_handle_irq(xe->heci_gsc.irq); | |
| 254 | + if (ret) | |
| 255 | + drm_err_ratelimited(&xe->drm, "error handling GSC irq: %d\n", ret); | |
| 256 | +} | |
| @@ -11,10 +11,15 @@ struct xe_device; · 10 unmodified lines | ||
| 11 | 11 | struct mei_aux_device; |
| 12 | 12 | |
| 13 | 13 | /* |
| 14 | − * The HECI1 bit corresponds to bit15 and HECI2 to bit14. | |
| 14 | + * GSC HECI1 bit corresponds to bit15 and HECI2 to bit14. | |
| 15 | 15 | * The reason for this is to allow growth for more interfaces in the future. |
| 16 | 16 | */ |
| 17 | −#define GSC_IRQ_INTF(_x) BIT(15 - (_x)) | |
| 17 | +#define GSC_IRQ_INTF(_x) BIT(15 - (_x)) | |
| 18 | + | |
| 19 | +/* | |
| 20 | + * CSC HECI1 bit corresponds to bit9 and HECI2 to bit10. | |
| 21 | + */ | |
| 22 | +#define CSC_IRQ_INTF(_x) BIT(9 + (_x)) | |
| 18 | 23 | |
| 19 | 24 | /** |
| 20 | 25 | * struct xe_heci_gsc - graphics security controller for xe, HECI interface |
| @@ -31,5 +36,6 @@ struct xe_heci_gsc { · 10 unmodified lines | ||
| 31 | 36 | void xe_heci_gsc_init(struct xe_device *xe); |
| 32 | 37 | void xe_heci_gsc_fini(struct xe_device *xe); |
| 33 | 38 | void xe_heci_gsc_irq_handler(struct xe_device *xe, u32 iir); |
| 39 | +void xe_heci_csc_irq_handler(struct xe_device *xe, u32 iir); | |
| 34 | 40 | |
| 35 | 41 | #endif /* __XE_HECI_GSC_DEV_H__ */ |
| @@ -459,6 +459,8 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg) · 458 unmodified lines | ||
| 459 | 459 | * the primary tile. |
| 460 | 460 | */ |
| 461 | 461 | if (id == 0) { |
| 462 | + if (HAS_HECI_CSCFI(xe)) | |
| 463 | + xe_heci_csc_irq_handler(xe, master_ctl); | |
| 462 | 464 | xe_display_irq_handler(xe, master_ctl); |
| 463 | 465 | gu_misc_iir = gu_misc_irq_ack(xe, master_ctl); |
| 464 | 466 | } |
| @@ -7,7 +7,7 @@ · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | #include <drm/drm_managed.h> |
| 9 | 9 | |
| 10 | −#include "regs/xe_sriov_regs.h" | |
| 10 | +#include "regs/xe_gt_regs.h" | |
| 11 | 11 | |
| 12 | 12 | #include "xe_assert.h" |
| 13 | 13 | #include "xe_bo.h" |
| @@ -71,7 +71,7 @@ static struct xe_lmtt_pt *lmtt_pt_alloc(struct xe_lmtt *lmtt, unsigned int level · 57 unmodified lines | ||
| 71 | 71 | lmtt->ops->lmtt_pte_num(level)), |
| 72 | 72 | ttm_bo_type_kernel, |
| 73 | 73 | XE_BO_FLAG_VRAM_IF_DGFX(lmtt_to_tile(lmtt)) | |
| 74 | − XE_BO_NEEDS_64K | XE_BO_FLAG_PINNED); | |
| 74 | + XE_BO_FLAG_NEEDS_64K | XE_BO_FLAG_PINNED); | |
| 75 | 75 | if (IS_ERR(bo)) { |
| 76 | 76 | err = PTR_ERR(bo); |
| 77 | 77 | goto out_free_pt; |
| @@ -73,6 +73,7 @@ struct xe_migrate { · 72 unmodified lines | ||
| 73 | 73 | #define NUM_PT_SLOTS 32 |
| 74 | 74 | #define LEVEL0_PAGE_TABLE_ENCODE_SIZE SZ_2M |
| 75 | 75 | #define MAX_NUM_PTE 512 |
| 76 | +#define IDENTITY_OFFSET 256ULL | |
| 76 | 77 | |
| 77 | 78 | /* |
| 78 | 79 | * Although MI_STORE_DATA_IMM's "length" field is 10-bits, 0x3FE is the largest |
| @@ -84,15 +85,14 @@ struct xe_migrate { · 5 unmodified lines | ||
| 84 | 85 | #define MAX_PTE_PER_SDI 0x1FE |
| 85 | 86 | |
| 86 | 87 | /** |
| 87 | − * xe_tile_migrate_engine() - Get this tile's migrate engine. | |
| 88 | + * xe_tile_migrate_exec_queue() - Get this tile's migrate exec queue. | |
| 88 | 89 | * @tile: The tile. |
| 89 | 90 | * |
| 90 | − * Returns the default migrate engine of this tile. | |
| 91 | − * TODO: Perhaps this function is slightly misplaced, and even unneeded? | |
| 91 | + * Returns the default migrate exec queue of this tile. | |
| 92 | 92 | * |
| 93 | − * Return: The default migrate engine | |
| 93 | + * Return: The default migrate exec queue | |
| 94 | 94 | */ |
| 95 | −struct xe_exec_queue *xe_tile_migrate_engine(struct xe_tile *tile) | |
| 95 | +struct xe_exec_queue *xe_tile_migrate_exec_queue(struct xe_tile *tile) | |
| 96 | 96 | { |
| 97 | 97 | return tile->migrate->q; |
| 98 | 98 | } |
| @@ -121,14 +121,64 @@ static u64 xe_migrate_vm_addr(u64 slot, u32 level) · 22 unmodified lines | ||
| 121 | 121 | return (slot + 1ULL) << xe_pt_shift(level + 1); |
| 122 | 122 | } |
| 123 | 123 | |
| 124 | −static u64 xe_migrate_vram_ofs(struct xe_device *xe, u64 addr) | |
| 124 | +static u64 xe_migrate_vram_ofs(struct xe_device *xe, u64 addr, bool is_comp_pte) | |
| 125 | 125 | { |
| 126 | 126 | /* |
| 127 | 127 | * Remove the DPA to get a correct offset into identity table for the |
| 128 | 128 | * migrate offset |
| 129 | 129 | */ |
| 130 | + u64 identity_offset = IDENTITY_OFFSET; | |
| 131 | + | |
| 132 | + if (GRAPHICS_VER(xe) >= 20 && is_comp_pte) | |
| 133 | + identity_offset += DIV_ROUND_UP_ULL(xe->mem.vram.actual_physical_size, SZ_1G); | |
| 134 | + | |
| 130 | 135 | addr -= xe->mem.vram.dpa_base; |
| 131 | − return addr + (256ULL << xe_pt_shift(2)); | |
| 136 | + return addr + (identity_offset << xe_pt_shift(2)); | |
| 137 | +} | |
| 138 | + | |
| 139 | +static void xe_migrate_program_identity(struct xe_device *xe, struct xe_vm *vm, struct xe_bo *bo, | |
| 140 | + u64 map_ofs, u64 vram_offset, u16 pat_index, u64 pt_2m_ofs) | |
| 141 | +{ | |
| 142 | + u64 pos, ofs, flags; | |
| 143 | + u64 entry; | |
| 144 | + /* XXX: Unclear if this should be usable_size? */ | |
| 145 | + u64 vram_limit = xe->mem.vram.actual_physical_size + | |
| 146 | + xe->mem.vram.dpa_base; | |
| 147 | + u32 level = 2; | |
| 148 | + | |
| 149 | + ofs = map_ofs + XE_PAGE_SIZE * level + vram_offset * 8; | |
| 150 | + flags = vm->pt_ops->pte_encode_addr(xe, 0, pat_index, level, | |
| 151 | + true, 0); | |
| 152 | + | |
| 153 | + xe_assert(xe, IS_ALIGNED(xe->mem.vram.usable_size, SZ_2M)); | |
| 154 | + | |
| 155 | + /* | |
| 156 | + * Use 1GB pages when possible, last chunk always use 2M | |
| 157 | + * pages as mixing reserved memory (stolen, WOCPM) with a single | |
| 158 | + * mapping is not allowed on certain platforms. | |
| 159 | + */ | |
| 160 | + for (pos = xe->mem.vram.dpa_base; pos < vram_limit; | |
| 161 | + pos += SZ_1G, ofs += 8) { | |
| 162 | + if (pos + SZ_1G >= vram_limit) { | |
| 163 | + entry = vm->pt_ops->pde_encode_bo(bo, pt_2m_ofs, | |
| 164 | + pat_index); | |
| 165 | + xe_map_wr(xe, &bo->vmap, ofs, u64, entry); | |
| 166 | + | |
| 167 | + flags = vm->pt_ops->pte_encode_addr(xe, 0, | |
| 168 | + pat_index, | |
| 169 | + level - 1, | |
| 170 | + true, 0); | |
| 171 | + | |
| 172 | + for (ofs = pt_2m_ofs; pos < vram_limit; | |
| 173 | + pos += SZ_2M, ofs += 8) | |
| 174 | + xe_map_wr(xe, &bo->vmap, ofs, u64, pos | flags); | |
| 175 | + break; /* Ensure pos == vram_limit assert correct */ | |
| 176 | + } | |
| 177 | + | |
| 178 | + xe_map_wr(xe, &bo->vmap, ofs, u64, pos | flags); | |
| 179 | + } | |
| 180 | + | |
| 181 | + xe_assert(xe, pos == vram_limit); | |
| 132 | 182 | } |
| 133 | 183 | |
| 134 | 184 | static int xe_migrate_prepare_vm(struct xe_tile *tile, struct xe_migrate *m, |
| @@ -137,11 +187,13 @@ static int xe_migrate_prepare_vm(struct xe_tile *tile, struct xe_migrate *m, · 2 unmodified lines | ||
| 137 | 187 | struct xe_device *xe = tile_to_xe(tile); |
| 138 | 188 | u16 pat_index = xe->pat.idx[XE_CACHE_WB]; |
| 139 | 189 | u8 id = tile->id; |
| 140 | − u32 num_entries = NUM_PT_SLOTS, num_level = vm->pt_root[id]->level, | |
| 141 | − num_setup = num_level + 1; | |
| 190 | + u32 num_entries = NUM_PT_SLOTS, num_level = vm->pt_root[id]->level; | |
| 191 | +#define VRAM_IDENTITY_MAP_COUNT 2 | |
| 192 | + u32 num_setup = num_level + VRAM_IDENTITY_MAP_COUNT; | |
| 193 | +#undef VRAM_IDENTITY_MAP_COUNT | |
| 142 | 194 | u32 map_ofs, level, i; |
| 143 | 195 | struct xe_bo *bo, *batch = tile->mem.kernel_bb_pool->bo; |
| 144 | − u64 entry, pt30_ofs; | |
| 196 | + u64 entry, pt29_ofs; | |
| 145 | 197 | |
| 146 | 198 | /* Can't bump NUM_PT_SLOTS too high */ |
| 147 | 199 | BUILD_BUG_ON(NUM_PT_SLOTS > SZ_2M/XE_PAGE_SIZE); |
| @@ -161,9 +213,9 @@ static int xe_migrate_prepare_vm(struct xe_tile *tile, struct xe_migrate *m, · 13 unmodified lines | ||
| 161 | 213 | if (IS_ERR(bo)) |
| 162 | 214 | return PTR_ERR(bo); |
| 163 | 215 | |
| 164 | − /* PT31 reserved for 2M identity map */ | |
| 165 | − pt30_ofs = bo->size - 2 * XE_PAGE_SIZE; | |
| 166 | − entry = vm->pt_ops->pde_encode_bo(bo, pt30_ofs, pat_index); | |
| 216 | + /* PT30 & PT31 reserved for 2M identity map */ | |
| 217 | + pt29_ofs = bo->size - 3 * XE_PAGE_SIZE; | |
| 218 | + entry = vm->pt_ops->pde_encode_bo(bo, pt29_ofs, pat_index); | |
| 167 | 219 | xe_pt_write(xe, &vm->pt_root[id]->bo->vmap, 0, entry); |
| 168 | 220 | |
| 169 | 221 | map_ofs = (num_entries - num_setup) * XE_PAGE_SIZE; |
| @@ -215,12 +267,12 @@ static int xe_migrate_prepare_vm(struct xe_tile *tile, struct xe_migrate *m, · 45 unmodified lines | ||
| 215 | 267 | } else { |
| 216 | 268 | u64 batch_addr = xe_bo_addr(batch, 0, XE_PAGE_SIZE); |
| 217 | 269 | |
| 218 | − m->batch_base_ofs = xe_migrate_vram_ofs(xe, batch_addr); | |
| 270 | + m->batch_base_ofs = xe_migrate_vram_ofs(xe, batch_addr, false); | |
| 219 | 271 | |
| 220 | 272 | if (xe->info.has_usm) { |
| 221 | 273 | batch = tile->primary_gt->usm.bb_pool->bo; |
| 222 | 274 | batch_addr = xe_bo_addr(batch, 0, XE_PAGE_SIZE); |
| 223 | − m->usm_batch_base_ofs = xe_migrate_vram_ofs(xe, batch_addr); | |
| 275 | + m->usm_batch_base_ofs = xe_migrate_vram_ofs(xe, batch_addr, false); | |
| 224 | 276 | } |
| 225 | 277 | } |
| 226 | 278 | |
| @@ -254,55 +306,36 @@ static int xe_migrate_prepare_vm(struct xe_tile *tile, struct xe_migrate *m, · 27 unmodified lines | ||
| 254 | 306 | |
| 255 | 307 | /* Identity map the entire vram at 256GiB offset */ |
| 256 | 308 | if (IS_DGFX(xe)) { |
| 257 | − u64 pos, ofs, flags; | |
| 258 | − /* XXX: Unclear if this should be usable_size? */ | |
| 259 | − u64 vram_limit = xe->mem.vram.actual_physical_size + | |
| 260 | − xe->mem.vram.dpa_base; | |
| 309 | + u64 pt30_ofs = bo->size - 2 * XE_PAGE_SIZE; | |
| 261 | 310 | |
| 262 | − level = 2; | |
| 263 | − ofs = map_ofs + XE_PAGE_SIZE * level + 256 * 8; | |
| 264 | − flags = vm->pt_ops->pte_encode_addr(xe, 0, pat_index, level, | |
| 265 | − true, 0); | |
| 266 | − | |
| 267 | − xe_assert(xe, IS_ALIGNED(xe->mem.vram.usable_size, SZ_2M)); | |
| 311 | + xe_migrate_program_identity(xe, vm, bo, map_ofs, IDENTITY_OFFSET, | |
| 312 | + pat_index, pt30_ofs); | |
| 313 | + xe_assert(xe, xe->mem.vram.actual_physical_size <= | |
| 314 | + (MAX_NUM_PTE - IDENTITY_OFFSET) * SZ_1G); | |
| 268 | 315 | |
| 269 | 316 | /* |
| 270 | − * Use 1GB pages when possible, last chunk always use 2M | |
| 271 | − * pages as mixing reserved memory (stolen, WOCPM) with a single | |
| 272 | − * mapping is not allowed on certain platforms. | |
| 317 | + * Identity map the entire vram for compressed pat_index for xe2+ | |
| 318 | + * if flat ccs is enabled. | |
| 273 | 319 | */ |
| 274 | − for (pos = xe->mem.vram.dpa_base; pos < vram_limit; | |
| 275 | − pos += SZ_1G, ofs += 8) { | |
| 276 | − if (pos + SZ_1G >= vram_limit) { | |
| 277 | − u64 pt31_ofs = bo->size - XE_PAGE_SIZE; | |
| 278 | − | |
| 279 | − entry = vm->pt_ops->pde_encode_bo(bo, pt31_ofs, | |
| 280 | − pat_index); | |
| 281 | − xe_map_wr(xe, &bo->vmap, ofs, u64, entry); | |
| 282 | − | |
| 283 | − flags = vm->pt_ops->pte_encode_addr(xe, 0, | |
| 284 | − pat_index, | |
| 285 | − level - 1, | |
| 286 | − true, 0); | |
| 287 | − | |
| 288 | − for (ofs = pt31_ofs; pos < vram_limit; | |
| 289 | − pos += SZ_2M, ofs += 8) | |
| 290 | − xe_map_wr(xe, &bo->vmap, ofs, u64, pos | flags); | |
| 291 | − break; /* Ensure pos == vram_limit assert correct */ | |
| 292 | − } | |
| 293 | − | |
| 294 | − xe_map_wr(xe, &bo->vmap, ofs, u64, pos | flags); | |
| 320 | + if (GRAPHICS_VER(xe) >= 20 && xe_device_has_flat_ccs(xe)) { | |
| 321 | + u16 comp_pat_index = xe->pat.idx[XE_CACHE_NONE_COMPRESSION]; | |
| 322 | + u64 vram_offset = IDENTITY_OFFSET + | |
| 323 | + DIV_ROUND_UP_ULL(xe->mem.vram.actual_physical_size, SZ_1G); | |
| 324 | + u64 pt31_ofs = bo->size - XE_PAGE_SIZE; | |
| 325 | + | |
| 326 | + xe_assert(xe, xe->mem.vram.actual_physical_size <= (MAX_NUM_PTE - | |
| 327 | + IDENTITY_OFFSET - IDENTITY_OFFSET / 2) * SZ_1G); | |
| 328 | + xe_migrate_program_identity(xe, vm, bo, map_ofs, vram_offset, | |
| 329 | + comp_pat_index, pt31_ofs); | |
| 295 | 330 | } |
| 296 | − | |
| 297 | − xe_assert(xe, pos == vram_limit); | |
| 298 | 331 | } |
| 299 | 332 | |
| 300 | 333 | /* |
| 301 | 334 | * Example layout created above, with root level = 3: |
| 302 | 335 | * [PT0...PT7]: kernel PT's for copy/clear; 64 or 4KiB PTE's |
| 303 | 336 | * [PT8]: Kernel PT for VM_BIND, 4 KiB PTE's |
| 304 | − * [PT9...PT27]: Userspace PT's for VM_BIND, 4 KiB PTE's | |
| 305 | − * [PT28 = PDE 0] [PT29 = PDE 1] [PT30 = PDE 2] [PT31 = 2M vram identity map] | |
| 337 | + * [PT9...PT26]: Userspace PT's for VM_BIND, 4 KiB PTE's | |
| 338 | + * [PT27 = PDE 0] [PT28 = PDE 1] [PT29 = PDE 2] [PT30 & PT31 = 2M vram identity map] | |
| 306 | 339 | * |
| 307 | 340 | * This makes the lowest part of the VM point to the pagetables. |
| 308 | 341 | * Hence the lowest 2M in the vm should point to itself, with a few writes |
| @@ -348,6 +381,11 @@ static u32 xe_migrate_usm_logical_mask(struct xe_gt *gt) · 39 unmodified lines | ||
| 348 | 381 | return logical_mask; |
| 349 | 382 | } |
| 350 | 383 | |
| 384 | +static bool xe_migrate_needs_ccs_emit(struct xe_device *xe) | |
| 385 | +{ | |
| 386 | + return xe_device_has_flat_ccs(xe) && !(GRAPHICS_VER(xe) >= 20 && IS_DGFX(xe)); | |
| 387 | +} | |
| 388 | + | |
| 351 | 389 | /** |
| 352 | 390 | * xe_migrate_init() - Initialize a migrate context |
| 353 | 391 | * @tile: Back-pointer to the tile we're initializing for. |
| @@ -421,7 +459,7 @@ struct xe_migrate *xe_migrate_init(struct xe_tile *tile) · 67 unmodified lines | ||
| 421 | 459 | return ERR_PTR(err); |
| 422 | 460 | |
| 423 | 461 | if (IS_DGFX(xe)) { |
| 424 | − if (xe_device_has_flat_ccs(xe)) | |
| 462 | + if (xe_migrate_needs_ccs_emit(xe)) | |
| 425 | 463 | /* min chunk size corresponds to 4K of CCS Metadata */ |
| 426 | 464 | m->min_chunk_size = SZ_4K * SZ_64K / |
| 427 | 465 | xe_device_ccs_bytes(xe, SZ_64K); |
| @@ -475,20 +513,26 @@ static bool xe_migrate_allow_identity(u64 size, const struct xe_res_cursor *cur) · 47 unmodified lines | ||
| 475 | 513 | return cur->size >= size; |
| 476 | 514 | } |
| 477 | 515 | |
| 516 | +#define PTE_UPDATE_FLAG_IS_VRAM BIT(0) | |
| 517 | +#define PTE_UPDATE_FLAG_IS_COMP_PTE BIT(1) | |
| 518 | + | |
| 478 | 519 | static u32 pte_update_size(struct xe_migrate *m, |
| 479 | − bool is_vram, | |
| 520 | + u32 flags, | |
| 480 | 521 | struct ttm_resource *res, |
| 481 | 522 | struct xe_res_cursor *cur, |
| 482 | 523 | u64 *L0, u64 *L0_ofs, u32 *L0_pt, |
| 483 | 524 | u32 cmd_size, u32 pt_ofs, u32 avail_pts) |
| 484 | 525 | { |
| 485 | 526 | u32 cmds = 0; |
| 527 | + bool is_vram = PTE_UPDATE_FLAG_IS_VRAM & flags; | |
| 528 | + bool is_comp_pte = PTE_UPDATE_FLAG_IS_COMP_PTE & flags; | |
| 486 | 529 | |
| 487 | 530 | *L0_pt = pt_ofs; |
| 488 | 531 | if (is_vram && xe_migrate_allow_identity(*L0, cur)) { |
| 489 | 532 | /* Offset into identity map. */ |
| 490 | 533 | *L0_ofs = xe_migrate_vram_ofs(tile_to_xe(m->tile), |
| 491 | − cur->start + vram_region_gpu_offset(res)); | |
| 534 | + cur->start + vram_region_gpu_offset(res), | |
| 535 | + is_comp_pte); | |
| 492 | 536 | cmds += cmd_size; |
| 493 | 537 | } else { |
| 494 | 538 | /* Clip L0 to available size */ |
| @@ -661,7 +705,7 @@ static u32 xe_migrate_ccs_copy(struct xe_migrate *m, · 166 unmodified lines | ||
| 661 | 705 | struct xe_gt *gt = m->tile->primary_gt; |
| 662 | 706 | u32 flush_flags = 0; |
| 663 | 707 | |
| 664 | − if (xe_device_has_flat_ccs(gt_to_xe(gt)) && !copy_ccs && dst_is_indirect) { | |
| 708 | + if (!copy_ccs && dst_is_indirect) { | |
| 665 | 709 | /* |
| 666 | 710 | * If the src is already in vram, then it should already |
| 667 | 711 | * have been cleared by us, or has been populated by the |
| @@ -737,6 +781,8 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, · 69 unmodified lines | ||
| 737 | 781 | bool copy_ccs = xe_device_has_flat_ccs(xe) && |
| 738 | 782 | xe_bo_needs_ccs_pages(src_bo) && xe_bo_needs_ccs_pages(dst_bo); |
| 739 | 783 | bool copy_system_ccs = copy_ccs && (!src_is_vram || !dst_is_vram); |
| 784 | + bool use_comp_pat = xe_device_has_flat_ccs(xe) && | |
| 785 | + GRAPHICS_VER(xe) >= 20 && src_is_vram && !dst_is_vram; | |
| 740 | 786 | |
| 741 | 787 | /* Copying CCS between two different BOs is not supported yet. */ |
| 742 | 788 | if (XE_WARN_ON(copy_ccs && src_bo != dst_bo)) |
| @@ -763,10 +809,11 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, · 20 unmodified lines | ||
| 763 | 809 | u32 batch_size = 2; /* arb_clear() + MI_BATCH_BUFFER_END */ |
| 764 | 810 | struct xe_sched_job *job; |
| 765 | 811 | struct xe_bb *bb; |
| 766 | − u32 flush_flags; | |
| 812 | + u32 flush_flags = 0; | |
| 767 | 813 | u32 update_idx; |
| 768 | 814 | u64 ccs_ofs, ccs_size; |
| 769 | 815 | u32 ccs_pt; |
| 816 | + u32 pte_flags; | |
| 770 | 817 | |
| 771 | 818 | bool usm = xe->info.has_usm; |
| 772 | 819 | u32 avail_pts = max_mem_transfer_per_pass(xe) / LEVEL0_PAGE_TABLE_ENCODE_SIZE; |
| @@ -779,17 +826,20 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, · 6 unmodified lines | ||
| 779 | 826 | |
| 780 | 827 | src_L0 = min(src_L0, dst_L0); |
| 781 | 828 | |
| 782 | − batch_size += pte_update_size(m, src_is_vram, src, &src_it, &src_L0, | |
| 829 | + pte_flags = src_is_vram ? PTE_UPDATE_FLAG_IS_VRAM : 0; | |
| 830 | + pte_flags |= use_comp_pat ? PTE_UPDATE_FLAG_IS_COMP_PTE : 0; | |
| 831 | + batch_size += pte_update_size(m, pte_flags, src, &src_it, &src_L0, | |
| 783 | 832 | &src_L0_ofs, &src_L0_pt, 0, 0, |
| 784 | 833 | avail_pts); |
| 785 | 834 | |
| 786 | − batch_size += pte_update_size(m, dst_is_vram, dst, &dst_it, &src_L0, | |
| 835 | + pte_flags = dst_is_vram ? PTE_UPDATE_FLAG_IS_VRAM : 0; | |
| 836 | + batch_size += pte_update_size(m, pte_flags, dst, &dst_it, &src_L0, | |
| 787 | 837 | &dst_L0_ofs, &dst_L0_pt, 0, |
| 788 | 838 | avail_pts, avail_pts); |
| 789 | 839 | |
| 790 | 840 | if (copy_system_ccs) { |
| 791 | 841 | ccs_size = xe_device_ccs_bytes(xe, src_L0); |
| 792 | − batch_size += pte_update_size(m, false, NULL, &ccs_it, &ccs_size, | |
| 842 | + batch_size += pte_update_size(m, 0, NULL, &ccs_it, &ccs_size, | |
| 793 | 843 | &ccs_ofs, &ccs_pt, 0, |
| 794 | 844 | 2 * avail_pts, |
| 795 | 845 | avail_pts); |
| @@ -798,7 +848,7 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, · 2 unmodified lines | ||
| 798 | 848 | |
| 799 | 849 | /* Add copy commands size here */ |
| 800 | 850 | batch_size += ((copy_only_ccs) ? 0 : EMIT_COPY_DW) + |
| 801 | − ((xe_device_has_flat_ccs(xe) ? EMIT_COPY_CCS_DW : 0)); | |
| 851 | + ((xe_migrate_needs_ccs_emit(xe) ? EMIT_COPY_CCS_DW : 0)); | |
| 802 | 852 | |
| 803 | 853 | bb = xe_bb_new(gt, batch_size, usm); |
| 804 | 854 | if (IS_ERR(bb)) { |
| @@ -827,11 +877,12 @@ struct dma_fence *xe_migrate_copy(struct xe_migrate *m, · 22 unmodified lines | ||
| 827 | 877 | if (!copy_only_ccs) |
| 828 | 878 | emit_copy(gt, bb, src_L0_ofs, dst_L0_ofs, src_L0, XE_PAGE_SIZE); |
| 829 | 879 | |
| 830 | − flush_flags = xe_migrate_ccs_copy(m, bb, src_L0_ofs, | |
| 831 | − IS_DGFX(xe) ? src_is_vram : src_is_pltt, | |
| 832 | − dst_L0_ofs, | |
| 833 | − IS_DGFX(xe) ? dst_is_vram : dst_is_pltt, | |
| 834 | − src_L0, ccs_ofs, copy_ccs); | |
| 880 | + if (xe_migrate_needs_ccs_emit(xe)) | |
| 881 | + flush_flags = xe_migrate_ccs_copy(m, bb, src_L0_ofs, | |
| 882 | + IS_DGFX(xe) ? src_is_vram : src_is_pltt, | |
| 883 | + dst_L0_ofs, | |
| 884 | + IS_DGFX(xe) ? dst_is_vram : dst_is_pltt, | |
| 885 | + src_L0, ccs_ofs, copy_ccs); | |
| 835 | 886 | |
| 836 | 887 | job = xe_bb_create_migration_job(m->q, bb, |
| 837 | 888 | xe_migrate_batch_base(m, usm), |
| @@ -1022,6 +1073,7 @@ struct dma_fence *xe_migrate_clear(struct xe_migrate *m, · 184 unmodified lines | ||
| 1022 | 1073 | struct xe_sched_job *job; |
| 1023 | 1074 | struct xe_bb *bb; |
| 1024 | 1075 | u32 batch_size, update_idx; |
| 1076 | + u32 pte_flags; | |
| 1025 | 1077 | |
| 1026 | 1078 | bool usm = xe->info.has_usm; |
| 1027 | 1079 | u32 avail_pts = max_mem_transfer_per_pass(xe) / LEVEL0_PAGE_TABLE_ENCODE_SIZE; |
| @@ -1029,13 +1081,14 @@ struct dma_fence *xe_migrate_clear(struct xe_migrate *m, · 1 unmodified line | ||
| 1029 | 1081 | clear_L0 = xe_migrate_res_sizes(m, &src_it); |
| 1030 | 1082 | |
| 1031 | 1083 | /* Calculate final sizes and batch size.. */ |
| 1084 | + pte_flags = clear_vram ? PTE_UPDATE_FLAG_IS_VRAM : 0; | |
| 1032 | 1085 | batch_size = 2 + |
| 1033 | − pte_update_size(m, clear_vram, src, &src_it, | |
| 1086 | + pte_update_size(m, pte_flags, src, &src_it, | |
| 1034 | 1087 | &clear_L0, &clear_L0_ofs, &clear_L0_pt, |
| 1035 | 1088 | clear_system_ccs ? 0 : emit_clear_cmd_len(gt), 0, |
| 1036 | 1089 | avail_pts); |
| 1037 | 1090 | |
| 1038 | − if (xe_device_has_flat_ccs(xe)) | |
| 1091 | + if (xe_migrate_needs_ccs_emit(xe)) | |
| 1039 | 1092 | batch_size += EMIT_COPY_CCS_DW; |
| 1040 | 1093 | |
| 1041 | 1094 | /* Clear commands */ |
| @@ -1063,7 +1116,7 @@ struct dma_fence *xe_migrate_clear(struct xe_migrate *m, · 21 unmodified lines | ||
| 1063 | 1116 | if (!clear_system_ccs) |
| 1064 | 1117 | emit_clear(gt, bb, clear_L0_ofs, clear_L0, XE_PAGE_SIZE, clear_vram); |
| 1065 | 1118 | |
| 1066 | − if (xe_device_has_flat_ccs(xe)) { | |
| 1119 | + if (xe_migrate_needs_ccs_emit(xe)) { | |
| 1067 | 1120 | emit_copy_ccs(gt, bb, clear_L0_ofs, true, |
| 1068 | 1121 | m->cleared_mem_ofs, false, clear_L0); |
| 1069 | 1122 | flush_flags = MI_FLUSH_DW_CCS; |
| @@ -1126,6 +1179,7 @@ err_sync: · 56 unmodified lines | ||
| 1126 | 1179 | } |
| 1127 | 1180 | |
| 1128 | 1181 | static void write_pgtable(struct xe_tile *tile, struct xe_bb *bb, u64 ppgtt_ofs, |
| 1182 | + const struct xe_vm_pgtable_update_op *pt_op, | |
| 1129 | 1183 | const struct xe_vm_pgtable_update *update, |
| 1130 | 1184 | struct xe_migrate_pt_update *pt_update) |
| 1131 | 1185 | { |
| @@ -1146,7 +1200,7 @@ static void write_pgtable(struct xe_tile *tile, struct xe_bb *bb, u64 ppgtt_ofs, · 14 unmodified lines | ||
| 1146 | 1200 | if (!ppgtt_ofs) |
| 1147 | 1201 | ppgtt_ofs = xe_migrate_vram_ofs(tile_to_xe(tile), |
| 1148 | 1202 | xe_bo_addr(update->pt_bo, 0, |
| 1149 | − XE_PAGE_SIZE)); | |
| 1203 | + XE_PAGE_SIZE), false); | |
| 1150 | 1204 | |
| 1151 | 1205 | do { |
| 1152 | 1206 | u64 addr = ppgtt_ofs + ofs * 8; |
| @@ -1160,8 +1214,12 @@ static void write_pgtable(struct xe_tile *tile, struct xe_bb *bb, u64 ppgtt_ofs, · 7 unmodified lines | ||
| 1160 | 1214 | bb->cs[bb->len++] = MI_STORE_DATA_IMM | MI_SDI_NUM_QW(chunk); |
| 1161 | 1215 | bb->cs[bb->len++] = lower_32_bits(addr); |
| 1162 | 1216 | bb->cs[bb->len++] = upper_32_bits(addr); |
| 1163 | − ops->populate(pt_update, tile, NULL, bb->cs + bb->len, ofs, chunk, | |
| 1164 | − update); | |
| 1217 | + if (pt_op->bind) | |
| 1218 | + ops->populate(pt_update, tile, NULL, bb->cs + bb->len, | |
| 1219 | + ofs, chunk, update); | |
| 1220 | + else | |
| 1221 | + ops->clear(pt_update, tile, NULL, bb->cs + bb->len, | |
| 1222 | + ofs, chunk, update); | |
| 1165 | 1223 | |
| 1166 | 1224 | bb->len += chunk * 2; |
| 1167 | 1225 | ofs += chunk; |
| @@ -1186,114 +1244,58 @@ struct migrate_test_params { · 18 unmodified lines | ||
| 1186 | 1244 | |
| 1187 | 1245 | static struct dma_fence * |
| 1188 | 1246 | xe_migrate_update_pgtables_cpu(struct xe_migrate *m, |
| 1189 | − struct xe_vm *vm, struct xe_bo *bo, | |
| 1190 | − const struct xe_vm_pgtable_update *updates, | |
| 1191 | − u32 num_updates, bool wait_vm, | |
| 1192 | 1247 | struct xe_migrate_pt_update *pt_update) |
| 1193 | 1248 | { |
| 1194 | 1249 | XE_TEST_DECLARE(struct migrate_test_params *test = |
| 1195 | 1250 | to_migrate_test_params |
| 1196 | 1251 | (xe_cur_kunit_priv(XE_TEST_LIVE_MIGRATE));) |
| 1197 | 1252 | const struct xe_migrate_pt_update_ops *ops = pt_update->ops; |
| 1198 | − struct dma_fence *fence; | |
| 1253 | + struct xe_vm *vm = pt_update->vops->vm; | |
| 1254 | + struct xe_vm_pgtable_update_ops *pt_update_ops = | |
| 1255 | + &pt_update->vops->pt_update_ops[pt_update->tile_id]; | |
| 1199 | 1256 | int err; |
| 1200 | − u32 i; | |
| 1257 | + u32 i, j; | |
| 1201 | 1258 | |
| 1202 | 1259 | if (XE_TEST_ONLY(test && test->force_gpu)) |
| 1203 | 1260 | return ERR_PTR(-ETIME); |
| 1204 | 1261 | |
| 1205 | − if (bo && !dma_resv_test_signaled(bo->ttm.base.resv, | |
| 1206 | − DMA_RESV_USAGE_KERNEL)) | |
| 1207 | − return ERR_PTR(-ETIME); | |
| 1208 | − | |
| 1209 | − if (wait_vm && !dma_resv_test_signaled(xe_vm_resv(vm), | |
| 1210 | − DMA_RESV_USAGE_BOOKKEEP)) | |
| 1211 | − return ERR_PTR(-ETIME); | |
| 1212 | − | |
| 1213 | 1262 | if (ops->pre_commit) { |
| 1214 | 1263 | pt_update->job = NULL; |
| 1215 | 1264 | err = ops->pre_commit(pt_update); |
| 1216 | 1265 | if (err) |
| 1217 | 1266 | return ERR_PTR(err); |
| 1218 | 1267 | } |
| 1219 | − for (i = 0; i < num_updates; i++) { | |
| 1220 | − const struct xe_vm_pgtable_update *update = &updates[i]; | |
| 1221 | − | |
| 1222 | − ops->populate(pt_update, m->tile, &update->pt_bo->vmap, NULL, | |
| 1223 | − update->ofs, update->qwords, update); | |
| 1224 | − } | |
| 1225 | − | |
| 1226 | − if (vm) { | |
| 1227 | − trace_xe_vm_cpu_bind(vm); | |
| 1228 | − xe_device_wmb(vm->xe); | |
| 1229 | − } | |
| 1230 | − | |
| 1231 | − fence = dma_fence_get_stub(); | |
| 1232 | − | |
| 1233 | − return fence; | |
| 1234 | −} | |
| 1235 | − | |
| 1236 | −static bool no_in_syncs(struct xe_vm *vm, struct xe_exec_queue *q, | |
| 1237 | − struct xe_sync_entry *syncs, u32 num_syncs) | |
| 1238 | −{ | |
| 1239 | − struct dma_fence *fence; | |
| 1240 | − int i; | |
| 1241 | 1268 | |
| 1242 | − for (i = 0; i < num_syncs; i++) { | |
| 1243 | − fence = syncs[i].fence; | |
| 1244 | − | |
| 1245 | − if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, | |
| 1246 | − &fence->flags)) | |
| 1247 | − return false; | |
| 1248 | − } | |
| 1249 | − if (q) { | |
| 1250 | − fence = xe_exec_queue_last_fence_get(q, vm); | |
| 1251 | − if (!test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { | |
| 1252 | − dma_fence_put(fence); | |
| 1253 | − return false; | |
| 1269 | + for (i = 0; i < pt_update_ops->num_ops; ++i) { | |
| 1270 | + const struct xe_vm_pgtable_update_op *pt_op = | |
| 1271 | + &pt_update_ops->ops[i]; | |
| 1272 | + | |
| 1273 | + for (j = 0; j < pt_op->num_entries; j++) { | |
| 1274 | + const struct xe_vm_pgtable_update *update = | |
| 1275 | + &pt_op->entries[j]; | |
| 1276 | + | |
| 1277 | + if (pt_op->bind) | |
| 1278 | + ops->populate(pt_update, m->tile, | |
| 1279 | + &update->pt_bo->vmap, NULL, | |
| 1280 | + update->ofs, update->qwords, | |
| 1281 | + update); | |
| 1282 | + else | |
| 1283 | + ops->clear(pt_update, m->tile, | |
| 1284 | + &update->pt_bo->vmap, NULL, | |
| 1285 | + update->ofs, update->qwords, update); | |
| 1254 | 1286 | } |
| 1255 | − dma_fence_put(fence); | |
| 1256 | 1287 | } |
| 1257 | 1288 | |
| 1258 | − return true; | |
| 1289 | + trace_xe_vm_cpu_bind(vm); | |
| 1290 | + xe_device_wmb(vm->xe); | |
| 1291 | + | |
| 1292 | + return dma_fence_get_stub(); | |
| 1259 | 1293 | } |
| 1260 | 1294 | |
| 1261 | −/** | |
| 1262 | − * xe_migrate_update_pgtables() - Pipelined page-table update | |
| 1263 | − * @m: The migrate context. | |
| 1264 | − * @vm: The vm we'll be updating. | |
| 1265 | − * @bo: The bo whose dma-resv we will await before updating, or NULL if userptr. | |
| 1266 | − * @q: The exec queue to be used for the update or NULL if the default | |
| 1267 | − * migration engine is to be used. | |
| 1268 | − * @updates: An array of update descriptors. | |
| 1269 | − * @num_updates: Number of descriptors in @updates. | |
| 1270 | − * @syncs: Array of xe_sync_entry to await before updating. Note that waits | |
| 1271 | − * will block the engine timeline. | |
| 1272 | − * @num_syncs: Number of entries in @syncs. | |
| 1273 | − * @pt_update: Pointer to a struct xe_migrate_pt_update, which contains | |
| 1274 | − * pointers to callback functions and, if subclassed, private arguments to | |
| 1275 | − * those. | |
| 1276 | − * | |
| 1277 | − * Perform a pipelined page-table update. The update descriptors are typically | |
| 1278 | − * built under the same lock critical section as a call to this function. If | |
| 1279 | − * using the default engine for the updates, they will be performed in the | |
| 1280 | − * order they grab the job_mutex. If different engines are used, external | |
| 1281 | − * synchronization is needed for overlapping updates to maintain page-table | |
| 1282 | − * consistency. Note that the meaing of "overlapping" is that the updates | |
| 1283 | − * touch the same page-table, which might be a higher-level page-directory. | |
| 1284 | − * If no pipelining is needed, then updates may be performed by the cpu. | |
| 1285 | − * | |
| 1286 | − * Return: A dma_fence that, when signaled, indicates the update completion. | |
| 1287 | − */ | |
| 1288 | −struct dma_fence * | |
| 1289 | −xe_migrate_update_pgtables(struct xe_migrate *m, | |
| 1290 | − struct xe_vm *vm, | |
| 1291 | − struct xe_bo *bo, | |
| 1292 | − struct xe_exec_queue *q, | |
| 1293 | − const struct xe_vm_pgtable_update *updates, | |
| 1294 | − u32 num_updates, | |
| 1295 | − struct xe_sync_entry *syncs, u32 num_syncs, | |
| 1296 | − struct xe_migrate_pt_update *pt_update) | |
| 1295 | +static struct dma_fence * | |
| 1296 | +__xe_migrate_update_pgtables(struct xe_migrate *m, | |
| 1297 | + struct xe_migrate_pt_update *pt_update, | |
| 1298 | + struct xe_vm_pgtable_update_ops *pt_update_ops) | |
| 1297 | 1299 | { |
| 1298 | 1300 | const struct xe_migrate_pt_update_ops *ops = pt_update->ops; |
| 1299 | 1301 | struct xe_tile *tile = m->tile; |
| @@ -1302,59 +1304,53 @@ xe_migrate_update_pgtables(struct xe_migrate *m, · 2 unmodified lines | ||
| 1302 | 1304 | struct xe_sched_job *job; |
| 1303 | 1305 | struct dma_fence *fence; |
| 1304 | 1306 | struct drm_suballoc *sa_bo = NULL; |
| 1305 | − struct xe_vma *vma = pt_update->vma; | |
| 1306 | 1307 | struct xe_bb *bb; |
| 1307 | − u32 i, batch_size, ppgtt_ofs, update_idx, page_ofs = 0; | |
| 1308 | + u32 i, j, batch_size = 0, ppgtt_ofs, update_idx, page_ofs = 0; | |
| 1309 | + u32 num_updates = 0, current_update = 0; | |
| 1308 | 1310 | u64 addr; |
| 1309 | 1311 | int err = 0; |
| 1310 | − bool usm = !q && xe->info.has_usm; | |
| 1311 | − bool first_munmap_rebind = vma && | |
| 1312 | − vma->gpuva.flags & XE_VMA_FIRST_REBIND; | |
| 1313 | − struct xe_exec_queue *q_override = !q ? m->q : q; | |
| 1314 | − u16 pat_index = xe->pat.idx[XE_CACHE_WB]; | |
| 1312 | + bool is_migrate = pt_update_ops->q == m->q; | |
| 1313 | + bool usm = is_migrate && xe->info.has_usm; | |
| 1314 | + | |
| 1315 | + for (i = 0; i < pt_update_ops->num_ops; ++i) { | |
| 1316 | + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[i]; | |
| 1317 | + struct xe_vm_pgtable_update *updates = pt_op->entries; | |
| 1315 | 1318 | |
| 1316 | − /* Use the CPU if no in syncs and engine is idle */ | |
| 1317 | − if (no_in_syncs(vm, q, syncs, num_syncs) && xe_exec_queue_is_idle(q_override)) { | |
| 1318 | − fence = xe_migrate_update_pgtables_cpu(m, vm, bo, updates, | |
| 1319 | − num_updates, | |
| 1320 | − first_munmap_rebind, | |
| 1321 | − pt_update); | |
| 1322 | − if (!IS_ERR(fence) || fence == ERR_PTR(-EAGAIN)) | |
| 1323 | − return fence; | |
| 1319 | + num_updates += pt_op->num_entries; | |
| 1320 | + for (j = 0; j < pt_op->num_entries; ++j) { | |
| 1321 | + u32 num_cmds = DIV_ROUND_UP(updates[j].qwords, | |
| 1322 | + MAX_PTE_PER_SDI); | |
| 1323 | + | |
| 1324 | + /* align noop + MI_STORE_DATA_IMM cmd prefix */ | |
| 1325 | + batch_size += 4 * num_cmds + updates[j].qwords * 2; | |
| 1326 | + } | |
| 1324 | 1327 | } |
| 1325 | 1328 | |
| 1326 | 1329 | /* fixed + PTE entries */ |
| 1327 | 1330 | if (IS_DGFX(xe)) |
| 1328 | − batch_size = 2; | |
| 1331 | + batch_size += 2; | |
| 1329 | 1332 | else |
| 1330 | − batch_size = 6 + num_updates * 2; | |
| 1331 | − | |
| 1332 | − for (i = 0; i < num_updates; i++) { | |
| 1333 | − u32 num_cmds = DIV_ROUND_UP(updates[i].qwords, MAX_PTE_PER_SDI); | |
| 1334 | − | |
| 1335 | − /* align noop + MI_STORE_DATA_IMM cmd prefix */ | |
| 1336 | − batch_size += 4 * num_cmds + updates[i].qwords * 2; | |
| 1337 | − } | |
| 1338 | − | |
| 1339 | − /* | |
| 1340 | − * XXX: Create temp bo to copy from, if batch_size becomes too big? | |
| 1341 | − * | |
| 1342 | − * Worst case: Sum(2 * (each lower level page size) + (top level page size)) | |
| 1343 | − * Should be reasonably bound.. | |
| 1344 | − */ | |
| 1345 | − xe_tile_assert(tile, batch_size < SZ_128K); | |
| 1333 | + batch_size += 6 * (num_updates / MAX_PTE_PER_SDI + 1) + | |
| 1334 | + num_updates * 2; | |
| 1346 | 1335 | |
| 1347 | − bb = xe_bb_new(gt, batch_size, !q && xe->info.has_usm); | |
| 1336 | + bb = xe_bb_new(gt, batch_size, usm); | |
| 1348 | 1337 | if (IS_ERR(bb)) |
| 1349 | 1338 | return ERR_CAST(bb); |
| 1350 | 1339 | |
| 1351 | 1340 | /* For sysmem PTE's, need to map them in our hole.. */ |
| 1352 | 1341 | if (!IS_DGFX(xe)) { |
| 1342 | + u32 ptes, ofs; | |
| 1343 | + | |
| 1353 | 1344 | ppgtt_ofs = NUM_KERNEL_PDE - 1; |
| 1354 | − if (q) { | |
| 1355 | − xe_tile_assert(tile, num_updates <= NUM_VMUSA_WRITES_PER_UNIT); | |
| 1345 | + if (!is_migrate) { | |
| 1346 | + u32 num_units = DIV_ROUND_UP(num_updates, | |
| 1347 | + NUM_VMUSA_WRITES_PER_UNIT); | |
| 1356 | 1348 | |
| 1357 | − sa_bo = drm_suballoc_new(&m->vm_update_sa, 1, | |
| 1349 | + if (num_units > m->vm_update_sa.size) { | |
| 1350 | + err = -ENOBUFS; | |
| 1351 | + goto err_bb; | |
| 1352 | + } | |
| 1353 | + sa_bo = drm_suballoc_new(&m->vm_update_sa, num_units, | |
| 1358 | 1354 | GFP_KERNEL, true, 0); |
| 1359 | 1355 | if (IS_ERR(sa_bo)) { |
| 1360 | 1356 | err = PTR_ERR(sa_bo); |
| @@ -1370,18 +1366,49 @@ xe_migrate_update_pgtables(struct xe_migrate *m, · 9 unmodified lines | ||
| 1370 | 1366 | } |
| 1371 | 1367 | |
| 1372 | 1368 | /* Map our PT's to gtt */ |
| 1373 | − bb->cs[bb->len++] = MI_STORE_DATA_IMM | MI_SDI_NUM_QW(num_updates); | |
| 1374 | − bb->cs[bb->len++] = ppgtt_ofs * XE_PAGE_SIZE + page_ofs; | |
| 1375 | − bb->cs[bb->len++] = 0; /* upper_32_bits */ | |
| 1376 | − | |
| 1377 | − for (i = 0; i < num_updates; i++) { | |
| 1378 | − struct xe_bo *pt_bo = updates[i].pt_bo; | |
| 1369 | + i = 0; | |
| 1370 | + j = 0; | |
| 1371 | + ptes = num_updates; | |
| 1372 | + ofs = ppgtt_ofs * XE_PAGE_SIZE + page_ofs; | |
| 1373 | + while (ptes) { | |
| 1374 | + u32 chunk = min(MAX_PTE_PER_SDI, ptes); | |
| 1375 | + u32 idx = 0; | |
| 1376 | + | |
| 1377 | + bb->cs[bb->len++] = MI_STORE_DATA_IMM | | |
| 1378 | + MI_SDI_NUM_QW(chunk); | |
| 1379 | + bb->cs[bb->len++] = ofs; | |
| 1380 | + bb->cs[bb->len++] = 0; /* upper_32_bits */ | |
| 1381 | + | |
| 1382 | + for (; i < pt_update_ops->num_ops; ++i) { | |
| 1383 | + struct xe_vm_pgtable_update_op *pt_op = | |
| 1384 | + &pt_update_ops->ops[i]; | |
| 1385 | + struct xe_vm_pgtable_update *updates = pt_op->entries; | |
| 1386 | + | |
| 1387 | + for (; j < pt_op->num_entries; ++j, ++current_update, ++idx) { | |
| 1388 | + struct xe_vm *vm = pt_update->vops->vm; | |
| 1389 | + struct xe_bo *pt_bo = updates[j].pt_bo; | |
| 1390 | + | |
| 1391 | + if (idx == chunk) | |
| 1392 | + goto next_cmd; | |
| 1393 | + | |
| 1394 | + xe_tile_assert(tile, pt_bo->size == SZ_4K); | |
| 1395 | + | |
| 1396 | + /* Map a PT at most once */ | |
| 1397 | + if (pt_bo->update_index < 0) | |
| 1398 | + pt_bo->update_index = current_update; | |
| 1399 | + | |
| 1400 | + addr = vm->pt_ops->pte_encode_bo(pt_bo, 0, | |
| 1401 | + XE_CACHE_WB, 0); | |
| 1402 | + bb->cs[bb->len++] = lower_32_bits(addr); | |
| 1403 | + bb->cs[bb->len++] = upper_32_bits(addr); | |
| 1404 | + } | |
| 1379 | 1405 | |
| 1380 | − xe_tile_assert(tile, pt_bo->size == SZ_4K); | |
| 1406 | + j = 0; | |
| 1407 | + } | |
| 1381 | 1408 | |
| 1382 | − addr = vm->pt_ops->pte_encode_bo(pt_bo, 0, pat_index, 0); | |
| 1383 | − bb->cs[bb->len++] = lower_32_bits(addr); | |
| 1384 | − bb->cs[bb->len++] = upper_32_bits(addr); | |
| 1409 | +next_cmd: | |
| 1410 | + ptes -= chunk; | |
| 1411 | + ofs += chunk * sizeof(u64); | |
| 1385 | 1412 | } |
| 1386 | 1413 | |
| 1387 | 1414 | bb->cs[bb->len++] = MI_BATCH_BUFFER_END; |
| @@ -1389,19 +1416,36 @@ xe_migrate_update_pgtables(struct xe_migrate *m, · 1 unmodified line | ||
| 1389 | 1416 | |
| 1390 | 1417 | addr = xe_migrate_vm_addr(ppgtt_ofs, 0) + |
| 1391 | 1418 | (page_ofs / sizeof(u64)) * XE_PAGE_SIZE; |
| 1392 | − for (i = 0; i < num_updates; i++) | |
| 1393 | − write_pgtable(tile, bb, addr + i * XE_PAGE_SIZE, | |
| 1394 | − &updates[i], pt_update); | |
| 1419 | + for (i = 0; i < pt_update_ops->num_ops; ++i) { | |
| 1420 | + struct xe_vm_pgtable_update_op *pt_op = | |
| 1421 | + &pt_update_ops->ops[i]; | |
| 1422 | + struct xe_vm_pgtable_update *updates = pt_op->entries; | |
| 1423 | + | |
| 1424 | + for (j = 0; j < pt_op->num_entries; ++j) { | |
| 1425 | + struct xe_bo *pt_bo = updates[j].pt_bo; | |
| 1426 | + | |
| 1427 | + write_pgtable(tile, bb, addr + | |
| 1428 | + pt_bo->update_index * XE_PAGE_SIZE, | |
| 1429 | + pt_op, &updates[j], pt_update); | |
| 1430 | + } | |
| 1431 | + } | |
| 1395 | 1432 | } else { |
| 1396 | 1433 | /* phys pages, no preamble required */ |
| 1397 | 1434 | bb->cs[bb->len++] = MI_BATCH_BUFFER_END; |
| 1398 | 1435 | update_idx = bb->len; |
| 1399 | 1436 | |
| 1400 | − for (i = 0; i < num_updates; i++) | |
| 1401 | − write_pgtable(tile, bb, 0, &updates[i], pt_update); | |
| 1437 | + for (i = 0; i < pt_update_ops->num_ops; ++i) { | |
| 1438 | + struct xe_vm_pgtable_update_op *pt_op = | |
| 1439 | + &pt_update_ops->ops[i]; | |
| 1440 | + struct xe_vm_pgtable_update *updates = pt_op->entries; | |
| 1441 | + | |
| 1442 | + for (j = 0; j < pt_op->num_entries; ++j) | |
| 1443 | + write_pgtable(tile, bb, 0, pt_op, &updates[j], | |
| 1444 | + pt_update); | |
| 1445 | + } | |
| 1402 | 1446 | } |
| 1403 | 1447 | |
| 1404 | − job = xe_bb_create_migration_job(q ?: m->q, bb, | |
| 1448 | + job = xe_bb_create_migration_job(pt_update_ops->q, bb, | |
| 1405 | 1449 | xe_migrate_batch_base(m, usm), |
| 1406 | 1450 | update_idx); |
| 1407 | 1451 | if (IS_ERR(job)) { |
| @@ -1409,46 +1453,20 @@ xe_migrate_update_pgtables(struct xe_migrate *m, · 1 unmodified line | ||
| 1409 | 1453 | goto err_sa; |
| 1410 | 1454 | } |
| 1411 | 1455 | |
| 1412 | − /* Wait on BO move */ | |
| 1413 | − if (bo) { | |
| 1414 | − err = xe_sched_job_add_deps(job, bo->ttm.base.resv, | |
| 1415 | − DMA_RESV_USAGE_KERNEL); | |
| 1416 | − if (err) | |
| 1417 | − goto err_job; | |
| 1418 | − } | |
| 1419 | − | |
| 1420 | − /* | |
| 1421 | − * Munmap style VM unbind, need to wait for all jobs to be complete / | |
| 1422 | − * trigger preempts before moving forward | |
| 1423 | − */ | |
| 1424 | − if (first_munmap_rebind) { | |
| 1425 | − err = xe_sched_job_add_deps(job, xe_vm_resv(vm), | |
| 1426 | − DMA_RESV_USAGE_BOOKKEEP); | |
| 1427 | − if (err) | |
| 1428 | − goto err_job; | |
| 1429 | − } | |
| 1430 | − | |
| 1431 | − err = xe_sched_job_last_fence_add_dep(job, vm); | |
| 1432 | − for (i = 0; !err && i < num_syncs; i++) | |
| 1433 | − err = xe_sync_entry_add_deps(&syncs[i], job); | |
| 1434 | − | |
| 1435 | − if (err) | |
| 1436 | − goto err_job; | |
| 1437 | − | |
| 1438 | 1456 | if (ops->pre_commit) { |
| 1439 | 1457 | pt_update->job = job; |
| 1440 | 1458 | err = ops->pre_commit(pt_update); |
| 1441 | 1459 | if (err) |
| 1442 | 1460 | goto err_job; |
| 1443 | 1461 | } |
| 1444 | − if (!q) | |
| 1462 | + if (is_migrate) | |
| 1445 | 1463 | mutex_lock(&m->job_mutex); |
| 1446 | 1464 | |
| 1447 | 1465 | xe_sched_job_arm(job); |
| 1448 | 1466 | fence = dma_fence_get(&job->drm.s_fence->finished); |
| 1449 | 1467 | xe_sched_job_push(job); |
| 1450 | 1468 | |
| 1451 | − if (!q) | |
| 1469 | + if (is_migrate) | |
| 1452 | 1470 | mutex_unlock(&m->job_mutex); |
| 1453 | 1471 | |
| 1454 | 1472 | xe_bb_free(bb, fence); |
| @@ -1465,6 +1483,40 @@ err_bb: · 10 unmodified lines | ||
| 1465 | 1483 | return ERR_PTR(err); |
| 1466 | 1484 | } |
| 1467 | 1485 | |
| 1486 | +/** | |
| 1487 | + * xe_migrate_update_pgtables() - Pipelined page-table update | |
| 1488 | + * @m: The migrate context. | |
| 1489 | + * @pt_update: PT update arguments | |
| 1490 | + * | |
| 1491 | + * Perform a pipelined page-table update. The update descriptors are typically | |
| 1492 | + * built under the same lock critical section as a call to this function. If | |
| 1493 | + * using the default engine for the updates, they will be performed in the | |
| 1494 | + * order they grab the job_mutex. If different engines are used, external | |
| 1495 | + * synchronization is needed for overlapping updates to maintain page-table | |
| 1496 | + * consistency. Note that the meaing of "overlapping" is that the updates | |
| 1497 | + * touch the same page-table, which might be a higher-level page-directory. | |
| 1498 | + * If no pipelining is needed, then updates may be performed by the cpu. | |
| 1499 | + * | |
| 1500 | + * Return: A dma_fence that, when signaled, indicates the update completion. | |
| 1501 | + */ | |
| 1502 | +struct dma_fence * | |
| 1503 | +xe_migrate_update_pgtables(struct xe_migrate *m, | |
| 1504 | + struct xe_migrate_pt_update *pt_update) | |
| 1505 | + | |
| 1506 | +{ | |
| 1507 | + struct xe_vm_pgtable_update_ops *pt_update_ops = | |
| 1508 | + &pt_update->vops->pt_update_ops[pt_update->tile_id]; | |
| 1509 | + struct dma_fence *fence; | |
| 1510 | + | |
| 1511 | + fence = xe_migrate_update_pgtables_cpu(m, pt_update); | |
| 1512 | + | |
| 1513 | + /* -ETIME indicates a job is needed, anything else is legit error */ | |
| 1514 | + if (!IS_ERR(fence) || PTR_ERR(fence) != -ETIME) | |
| 1515 | + return fence; | |
| 1516 | + | |
| 1517 | + return __xe_migrate_update_pgtables(m, pt_update, pt_update_ops); | |
| 1518 | +} | |
| 1519 | + | |
| 1468 | 1520 | /** |
| 1469 | 1521 | * xe_migrate_wait() - Complete all operations using the xe_migrate context |
| 1470 | 1522 | * @m: Migrate context to wait for. |
| @@ -47,6 +47,24 @@ struct xe_migrate_pt_update_ops { · 46 unmodified lines | ||
| 47 | 47 | struct xe_tile *tile, struct iosys_map *map, |
| 48 | 48 | void *pos, u32 ofs, u32 num_qwords, |
| 49 | 49 | const struct xe_vm_pgtable_update *update); |
| 50 | + /** | |
| 51 | + * @clear: Clear a command buffer or page-table with ptes. | |
| 52 | + * @pt_update: Embeddable callback argument. | |
| 53 | + * @tile: The tile for the current operation. | |
| 54 | + * @map: struct iosys_map into the memory to be populated. | |
| 55 | + * @pos: If @map is NULL, map into the memory to be populated. | |
| 56 | + * @ofs: qword offset into @map, unused if @map is NULL. | |
| 57 | + * @num_qwords: Number of qwords to write. | |
| 58 | + * @update: Information about the PTEs to be inserted. | |
| 59 | + * | |
| 60 | + * This interface is intended to be used as a callback into the | |
| 61 | + * page-table system to populate command buffers or shared | |
| 62 | + * page-tables with PTEs. | |
| 63 | + */ | |
| 64 | + void (*clear)(struct xe_migrate_pt_update *pt_update, | |
| 65 | + struct xe_tile *tile, struct iosys_map *map, | |
| 66 | + void *pos, u32 ofs, u32 num_qwords, | |
| 67 | + const struct xe_vm_pgtable_update *update); | |
| 50 | 68 | |
| 51 | 69 | /** |
| 52 | 70 | * @pre_commit: Callback to be called just before arming the |
| @@ -67,14 +85,10 @@ struct xe_migrate_pt_update_ops { · 14 unmodified lines | ||
| 67 | 85 | struct xe_migrate_pt_update { |
| 68 | 86 | /** @ops: Pointer to the struct xe_migrate_pt_update_ops callbacks */ |
| 69 | 87 | const struct xe_migrate_pt_update_ops *ops; |
| 70 | − /** @vma: The vma we're updating the pagetable for. */ | |
| 71 | − struct xe_vma *vma; | |
| 88 | + /** @vops: VMA operations */ | |
| 89 | + struct xe_vma_ops *vops; | |
| 72 | 90 | /** @job: The job if a GPU page-table update. NULL otherwise */ |
| 73 | 91 | struct xe_sched_job *job; |
| 74 | − /** @start: Start of update for the range fence */ | |
| 75 | − u64 start; | |
| 76 | − /** @last: Last of update for the range fence */ | |
| 77 | − u64 last; | |
| 78 | 92 | /** @tile_id: Tile ID of the update */ |
| 79 | 93 | u8 tile_id; |
| 80 | 94 | }; |
| @@ -96,15 +110,9 @@ struct xe_vm *xe_migrate_get_vm(struct xe_migrate *m); · 15 unmodified lines | ||
| 96 | 110 | |
| 97 | 111 | struct dma_fence * |
| 98 | 112 | xe_migrate_update_pgtables(struct xe_migrate *m, |
| 99 | − struct xe_vm *vm, | |
| 100 | − struct xe_bo *bo, | |
| 101 | − struct xe_exec_queue *q, | |
| 102 | − const struct xe_vm_pgtable_update *updates, | |
| 103 | − u32 num_updates, | |
| 104 | − struct xe_sync_entry *syncs, u32 num_syncs, | |
| 105 | 113 | struct xe_migrate_pt_update *pt_update); |
| 106 | 114 | |
| 107 | 115 | void xe_migrate_wait(struct xe_migrate *m); |
| 108 | 116 | |
| 109 | −struct xe_exec_queue *xe_tile_migrate_engine(struct xe_tile *tile); | |
| 117 | +struct xe_exec_queue *xe_tile_migrate_exec_queue(struct xe_tile *tile); | |
| 110 | 118 | #endif |
| @@ -33,29 +33,56 @@ static void tiles_fini(void *arg) · 32 unmodified lines | ||
| 33 | 33 | tile->mmio.regs = NULL; |
| 34 | 34 | } |
| 35 | 35 | |
| 36 | −int xe_mmio_probe_tiles(struct xe_device *xe) | |
| 36 | +/* | |
| 37 | + * On multi-tile devices, partition the BAR space for MMIO on each tile, | |
| 38 | + * possibly accounting for register override on the number of tiles available. | |
| 39 | + * Resulting memory layout is like below: | |
| 40 | + * | |
| 41 | + * .----------------------. <- tile_count * tile_mmio_size | |
| 42 | + * | .... | | |
| 43 | + * |----------------------| <- 2 * tile_mmio_size | |
| 44 | + * | tile1->mmio.regs | | |
| 45 | + * |----------------------| <- 1 * tile_mmio_size | |
| 46 | + * | tile0->mmio.regs | | |
| 47 | + * '----------------------' <- 0MB | |
| 48 | + */ | |
| 49 | +static void mmio_multi_tile_setup(struct xe_device *xe, size_t tile_mmio_size) | |
| 37 | 50 | { |
| 38 | − size_t tile_mmio_size = SZ_16M, tile_mmio_ext_size = xe->info.tile_mmio_ext_size; | |
| 39 | − u8 id, tile_count = xe->info.tile_count; | |
| 40 | − struct xe_gt *gt = xe_root_mmio_gt(xe); | |
| 41 | 51 | struct xe_tile *tile; |
| 42 | 52 | void __iomem *regs; |
| 43 | − u32 mtcfg; | |
| 53 | + u8 id; | |
| 44 | 54 | |
| 45 | − if (tile_count == 1) | |
| 46 | − goto add_mmio_ext; | |
| 55 | + /* | |
| 56 | + * Nothing to be done as tile 0 has already been setup earlier with the | |
| 57 | + * entire BAR mapped - see xe_mmio_init() | |
| 58 | + */ | |
| 59 | + if (xe->info.tile_count == 1) | |
| 60 | + return; | |
| 47 | 61 | |
| 62 | + /* Possibly override number of tile based on configuration register */ | |
| 48 | 63 | if (!xe->info.skip_mtcfg) { |
| 64 | + struct xe_gt *gt = xe_root_mmio_gt(xe); | |
| 65 | + u8 tile_count; | |
| 66 | + u32 mtcfg; | |
| 67 | + | |
| 68 | + /* | |
| 69 | + * Although the per-tile mmio regs are not yet initialized, this | |
| 70 | + * is fine as it's going to the root gt, that's guaranteed to be | |
| 71 | + * initialized earlier in xe_mmio_init() | |
| 72 | + */ | |
| 49 | 73 | mtcfg = xe_mmio_read64_2x32(gt, XEHP_MTCFG_ADDR); |
| 50 | 74 | tile_count = REG_FIELD_GET(TILE_COUNT, mtcfg) + 1; |
| 75 | + | |
| 51 | 76 | if (tile_count < xe->info.tile_count) { |
| 52 | 77 | drm_info(&xe->drm, "tile_count: %d, reduced_tile_count %d\n", |
| 53 | 78 | xe->info.tile_count, tile_count); |
| 54 | 79 | xe->info.tile_count = tile_count; |
| 55 | 80 | |
| 56 | 81 | /* |
| 57 | − * FIXME: Needs some work for standalone media, but should be impossible | |
| 58 | − * with multi-tile for now. | |
| 82 | + * FIXME: Needs some work for standalone media, but | |
| 83 | + * should be impossible with multi-tile for now: | |
| 84 | + * multi-tile platform with standalone media doesn't | |
| 85 | + * exist | |
| 59 | 86 | */ |
| 60 | 87 | xe->info.gt_count = xe->info.tile_count; |
| 61 | 88 | } |
| @@ -67,23 +94,51 @@ int xe_mmio_probe_tiles(struct xe_device *xe) · 5 unmodified lines | ||
| 67 | 94 | tile->mmio.regs = regs; |
| 68 | 95 | regs += tile_mmio_size; |
| 69 | 96 | } |
| 97 | +} | |
| 70 | 98 | |
| 71 | −add_mmio_ext: | |
| 72 | − /* | |
| 73 | − * By design, there's a contiguous multi-tile MMIO space (16MB hard coded per tile). | |
| 74 | − * When supported, there could be an additional contiguous multi-tile MMIO extension | |
| 75 | − * space ON TOP of it, and hence the necessity for distinguished MMIO spaces. | |
| 76 | − */ | |
| 77 | − if (xe->info.has_mmio_ext) { | |
| 78 | − regs = xe->mmio.regs + tile_mmio_size * tile_count; | |
| 99 | +/* | |
| 100 | + * On top of all the multi-tile MMIO space there can be a platform-dependent | |
| 101 | + * extension for each tile, resulting in a layout like below: | |
| 102 | + * | |
| 103 | + * .----------------------. <- ext_base + tile_count * tile_mmio_ext_size | |
| 104 | + * | .... | | |
| 105 | + * |----------------------| <- ext_base + 2 * tile_mmio_ext_size | |
| 106 | + * | tile1->mmio_ext.regs | | |
| 107 | + * |----------------------| <- ext_base + 1 * tile_mmio_ext_size | |
| 108 | + * | tile0->mmio_ext.regs | | |
| 109 | + * |======================| <- ext_base = tile_count * tile_mmio_size | |
| 110 | + * | | | |
| 111 | + * | mmio.regs | | |
| 112 | + * | | | |
| 113 | + * '----------------------' <- 0MB | |
| 114 | + * | |
| 115 | + * Set up the tile[]->mmio_ext pointers/sizes. | |
| 116 | + */ | |
| 117 | +static void mmio_extension_setup(struct xe_device *xe, size_t tile_mmio_size, | |
| 118 | + size_t tile_mmio_ext_size) | |
| 119 | +{ | |
| 120 | + struct xe_tile *tile; | |
| 121 | + void __iomem *regs; | |
| 122 | + u8 id; | |
| 79 | 123 | |
| 80 | − for_each_tile(tile, xe, id) { | |
| 81 | − tile->mmio_ext.size = tile_mmio_ext_size; | |
| 82 | − tile->mmio_ext.regs = regs; | |
| 124 | + if (!xe->info.has_mmio_ext) | |
| 125 | + return; | |
| 83 | 126 | |
| 84 | − regs += tile_mmio_ext_size; | |
| 85 | − } | |
| 127 | + regs = xe->mmio.regs + tile_mmio_size * xe->info.tile_count; | |
| 128 | + for_each_tile(tile, xe, id) { | |
| 129 | + tile->mmio_ext.size = tile_mmio_ext_size; | |
| 130 | + tile->mmio_ext.regs = regs; | |
| 131 | + regs += tile_mmio_ext_size; | |
| 86 | 132 | } |
| 133 | +} | |
| 134 | + | |
| 135 | +int xe_mmio_probe_tiles(struct xe_device *xe) | |
| 136 | +{ | |
| 137 | + size_t tile_mmio_size = SZ_16M; | |
| 138 | + size_t tile_mmio_ext_size = xe->info.tile_mmio_ext_size; | |
| 139 | + | |
| 140 | + mmio_multi_tile_setup(xe, tile_mmio_size); | |
| 141 | + mmio_extension_setup(xe, tile_mmio_size, tile_mmio_ext_size); | |
| 87 | 142 | |
| 88 | 143 | return devm_add_action_or_reset(xe->drm.dev, tiles_fini, xe); |
| 89 | 144 | } |
| @@ -121,12 +176,29 @@ int xe_mmio_init(struct xe_device *xe) · 31 unmodified lines | ||
| 121 | 176 | return devm_add_action_or_reset(xe->drm.dev, mmio_fini, xe); |
| 122 | 177 | } |
| 123 | 178 | |
| 179 | +static void mmio_flush_pending_writes(struct xe_gt *gt) | |
| 180 | +{ | |
| 181 | +#define DUMMY_REG_OFFSET 0x130030 | |
| 182 | + struct xe_tile *tile = gt_to_tile(gt); | |
| 183 | + int i; | |
| 184 | + | |
| 185 | + if (tile->xe->info.platform != XE_LUNARLAKE) | |
| 186 | + return; | |
| 187 | + | |
| 188 | + /* 4 dummy writes */ | |
| 189 | + for (i = 0; i < 4; i++) | |
| 190 | + writel(0, tile->mmio.regs + DUMMY_REG_OFFSET); | |
| 191 | +} | |
| 192 | + | |
| 124 | 193 | u8 xe_mmio_read8(struct xe_gt *gt, struct xe_reg reg) |
| 125 | 194 | { |
| 126 | 195 | struct xe_tile *tile = gt_to_tile(gt); |
| 127 | 196 | u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); |
| 128 | 197 | u8 val; |
| 129 | 198 | |
| 199 | + /* Wa_15015404425 */ | |
| 200 | + mmio_flush_pending_writes(gt); | |
| 201 | + | |
| 130 | 202 | val = readb((reg.ext ? tile->mmio_ext.regs : tile->mmio.regs) + addr); |
| 131 | 203 | trace_xe_reg_rw(gt, false, addr, val, sizeof(val)); |
| 132 | 204 | |
| @@ -139,6 +211,9 @@ u16 xe_mmio_read16(struct xe_gt *gt, struct xe_reg reg) · 6 unmodified lines | ||
| 139 | 211 | u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); |
| 140 | 212 | u16 val; |
| 141 | 213 | |
| 214 | + /* Wa_15015404425 */ | |
| 215 | + mmio_flush_pending_writes(gt); | |
| 216 | + | |
| 142 | 217 | val = readw((reg.ext ? tile->mmio_ext.regs : tile->mmio.regs) + addr); |
| 143 | 218 | trace_xe_reg_rw(gt, false, addr, val, sizeof(val)); |
| 144 | 219 | |
| @@ -151,7 +226,11 @@ void xe_mmio_write32(struct xe_gt *gt, struct xe_reg reg, u32 val) · 6 unmodified lines | ||
| 151 | 226 | u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); |
| 152 | 227 | |
| 153 | 228 | trace_xe_reg_rw(gt, true, addr, val, sizeof(val)); |
| 154 | − writel(val, (reg.ext ? tile->mmio_ext.regs : tile->mmio.regs) + addr); | |
| 229 | + | |
| 230 | + if (!reg.vf && IS_SRIOV_VF(gt_to_xe(gt))) | |
| 231 | + xe_gt_sriov_vf_write32(gt, reg, val); | |
| 232 | + else | |
| 233 | + writel(val, (reg.ext ? tile->mmio_ext.regs : tile->mmio.regs) + addr); | |
| 155 | 234 | } |
| 156 | 235 | |
| 157 | 236 | u32 xe_mmio_read32(struct xe_gt *gt, struct xe_reg reg) |
| @@ -160,6 +239,9 @@ u32 xe_mmio_read32(struct xe_gt *gt, struct xe_reg reg) · 2 unmodified lines | ||
| 160 | 239 | u32 addr = xe_mmio_adjusted_addr(gt, reg.addr); |
| 161 | 240 | u32 val; |
| 162 | 241 | |
| 242 | + /* Wa_15015404425 */ | |
| 243 | + mmio_flush_pending_writes(gt); | |
| 244 | + | |
| 163 | 245 | if (!reg.vf && IS_SRIOV_VF(gt_to_xe(gt))) |
| 164 | 246 | val = xe_gt_sriov_vf_read32(gt, reg); |
| 165 | 247 | else |
| @@ -251,37 +333,24 @@ u64 xe_mmio_read64_2x32(struct xe_gt *gt, struct xe_reg reg) · 85 unmodified lines | ||
| 251 | 333 | return (u64)udw << 32 | ldw; |
| 252 | 334 | } |
| 253 | 335 | |
| 254 | −/** | |
| 255 | − * xe_mmio_wait32() - Wait for a register to match the desired masked value | |
| 256 | − * @gt: MMIO target GT | |
| 257 | − * @reg: register to read value from | |
| 258 | − * @mask: mask to be applied to the value read from the register | |
| 259 | − * @val: desired value after applying the mask | |
| 260 | − * @timeout_us: time out after this period of time. Wait logic tries to be | |
| 261 | − * smart, applying an exponential backoff until @timeout_us is reached. | |
| 262 | − * @out_val: if not NULL, points where to store the last unmasked value | |
| 263 | − * @atomic: needs to be true if calling from an atomic context | |
| 264 | − * | |
| 265 | − * This function polls for the desired masked value and returns zero on success | |
| 266 | − * or -ETIMEDOUT if timed out. | |
| 267 | − * | |
| 268 | − * Note that @timeout_us represents the minimum amount of time to wait before | |
| 269 | − * giving up. The actual time taken by this function can be a little more than | |
| 270 | − * @timeout_us for different reasons, specially in non-atomic contexts. Thus, | |
| 271 | − * it is possible that this function succeeds even after @timeout_us has passed. | |
| 272 | − */ | |
| 273 | −int xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, | |
| 274 | − u32 *out_val, bool atomic) | |
| 336 | +static int __xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, | |
| 337 | + u32 *out_val, bool atomic, bool expect_match) | |
| 275 | 338 | { |
| 276 | 339 | ktime_t cur = ktime_get_raw(); |
| 277 | 340 | const ktime_t end = ktime_add_us(cur, timeout_us); |
| 278 | 341 | int ret = -ETIMEDOUT; |
| 279 | 342 | s64 wait = 10; |
| 280 | 343 | u32 read; |
| 344 | + bool check; | |
| 281 | 345 | |
| 282 | 346 | for (;;) { |
| 283 | 347 | read = xe_mmio_read32(gt, reg); |
| 284 | − if ((read & mask) == val) { | |
| 348 | + | |
| 349 | + check = (read & mask) == val; | |
| 350 | + if (!expect_match) | |
| 351 | + check = !check; | |
| 352 | + | |
| 353 | + if (check) { | |
| 285 | 354 | ret = 0; |
| 286 | 355 | break; |
| 287 | 356 | } |
| @@ -302,7 +371,12 @@ int xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 t · 14 unmodified lines | ||
| 302 | 371 | |
| 303 | 372 | if (ret != 0) { |
| 304 | 373 | read = xe_mmio_read32(gt, reg); |
| 305 | − if ((read & mask) == val) | |
| 374 | + | |
| 375 | + check = (read & mask) == val; | |
| 376 | + if (!expect_match) | |
| 377 | + check = !check; | |
| 378 | + | |
| 379 | + if (check) | |
| 306 | 380 | ret = 0; |
| 307 | 381 | } |
| 308 | 382 | |
| @@ -313,62 +387,45 @@ int xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 t · 4 unmodified lines | ||
| 313 | 387 | } |
| 314 | 388 | |
| 315 | 389 | /** |
| 316 | − * xe_mmio_wait32_not() - Wait for a register to return anything other than the given masked value | |
| 390 | + * xe_mmio_wait32() - Wait for a register to match the desired masked value | |
| 317 | 391 | * @gt: MMIO target GT |
| 318 | 392 | * @reg: register to read value from |
| 319 | 393 | * @mask: mask to be applied to the value read from the register |
| 320 | − * @val: value to match after applying the mask | |
| 394 | + * @val: desired value after applying the mask | |
| 321 | 395 | * @timeout_us: time out after this period of time. Wait logic tries to be |
| 322 | 396 | * smart, applying an exponential backoff until @timeout_us is reached. |
| 323 | 397 | * @out_val: if not NULL, points where to store the last unmasked value |
| 324 | 398 | * @atomic: needs to be true if calling from an atomic context |
| 325 | 399 | * |
| 326 | − * This function polls for a masked value to change from a given value and | |
| 327 | − * returns zero on success or -ETIMEDOUT if timed out. | |
| 400 | + * This function polls for the desired masked value and returns zero on success | |
| 401 | + * or -ETIMEDOUT if timed out. | |
| 328 | 402 | * |
| 329 | 403 | * Note that @timeout_us represents the minimum amount of time to wait before |
| 330 | 404 | * giving up. The actual time taken by this function can be a little more than |
| 331 | 405 | * @timeout_us for different reasons, specially in non-atomic contexts. Thus, |
| 332 | 406 | * it is possible that this function succeeds even after @timeout_us has passed. |
| 333 | 407 | */ |
| 408 | +int xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, | |
| 409 | + u32 *out_val, bool atomic) | |
| 410 | +{ | |
| 411 | + return __xe_mmio_wait32(gt, reg, mask, val, timeout_us, out_val, atomic, true); | |
| 412 | +} | |
| 413 | + | |
| 414 | +/** | |
| 415 | + * xe_mmio_wait32_not() - Wait for a register to return anything other than the given masked value | |
| 416 | + * @gt: MMIO target GT | |
| 417 | + * @reg: register to read value from | |
| 418 | + * @mask: mask to be applied to the value read from the register | |
| 419 | + * @val: value not to be matched after applying the mask | |
| 420 | + * @timeout_us: time out after this period of time | |
| 421 | + * @out_val: if not NULL, points where to store the last unmasked value | |
| 422 | + * @atomic: needs to be true if calling from an atomic context | |
| 423 | + * | |
| 424 | + * This function works exactly like xe_mmio_wait32() with the exception that | |
| 425 | + * @val is expected not to be matched. | |
| 426 | + */ | |
| 334 | 427 | int xe_mmio_wait32_not(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, |
| 335 | 428 | u32 *out_val, bool atomic) |
| 336 | 429 | { |
| 337 | − ktime_t cur = ktime_get_raw(); | |
| 338 | − const ktime_t end = ktime_add_us(cur, timeout_us); | |
| 339 | − int ret = -ETIMEDOUT; | |
| 340 | − s64 wait = 10; | |
| 341 | − u32 read; | |
| 342 | − | |
| 343 | − for (;;) { | |
| 344 | − read = xe_mmio_read32(gt, reg); | |
| 345 | − if ((read & mask) != val) { | |
| 346 | − ret = 0; | |
| 347 | − break; | |
| 348 | − } | |
| 349 | − | |
| 350 | − cur = ktime_get_raw(); | |
| 351 | − if (!ktime_before(cur, end)) | |
| 352 | − break; | |
| 353 | − | |
| 354 | − if (ktime_after(ktime_add_us(cur, wait), end)) | |
| 355 | − wait = ktime_us_delta(end, cur); | |
| 356 | − | |
| 357 | − if (atomic) | |
| 358 | − udelay(wait); | |
| 359 | − else | |
| 360 | − usleep_range(wait, wait << 1); | |
| 361 | − wait <<= 1; | |
| 362 | − } | |
| 363 | − | |
| 364 | − if (ret != 0) { | |
| 365 | − read = xe_mmio_read32(gt, reg); | |
| 366 | − if ((read & mask) != val) | |
| 367 | − ret = 0; | |
| 368 | − } | |
| 369 | − | |
| 370 | − if (out_val) | |
| 371 | − *out_val = read; | |
| 372 | − | |
| 373 | − return ret; | |
| 430 | + return __xe_mmio_wait32(gt, reg, mask, val, timeout_us, out_val, atomic, false); | |
| 374 | 431 | } |
| @@ -22,7 +22,6 @@ u32 xe_mmio_rmw32(struct xe_gt *gt, struct xe_reg reg, u32 clr, u32 set); · 21 unmodified lines | ||
| 22 | 22 | int xe_mmio_write32_and_verify(struct xe_gt *gt, struct xe_reg reg, u32 val, u32 mask, u32 eval); |
| 23 | 23 | bool xe_mmio_in_range(const struct xe_gt *gt, const struct xe_mmio_range *range, struct xe_reg reg); |
| 24 | 24 | |
| 25 | −int xe_mmio_probe_vram(struct xe_device *xe); | |
| 26 | 25 | u64 xe_mmio_read64_2x32(struct xe_gt *gt, struct xe_reg reg); |
| 27 | 26 | int xe_mmio_wait32(struct xe_gt *gt, struct xe_reg reg, u32 mask, u32 val, u32 timeout_us, |
| 28 | 27 | u32 *out_val, bool atomic); |
| @@ -641,7 +641,7 @@ static void xe_oa_store_flex(struct xe_oa_stream *stream, struct xe_lrc *lrc, · 640 unmodified lines | ||
| 641 | 641 | u32 offset = xe_bo_ggtt_addr(lrc->bo); |
| 642 | 642 | |
| 643 | 643 | do { |
| 644 | − bb->cs[bb->len++] = MI_STORE_DATA_IMM | BIT(22) /* GGTT */ | 2; | |
| 644 | + bb->cs[bb->len++] = MI_STORE_DATA_IMM | MI_SDI_GGTT | MI_SDI_NUM_DW(1); | |
| 645 | 645 | bb->cs[bb->len++] = offset + flex->offset * sizeof(u32); |
| 646 | 646 | bb->cs[bb->len++] = 0; |
| 647 | 647 | bb->cs[bb->len++] = flex->value; |
| @@ -7,6 +7,8 @@ · 6 unmodified lines | ||
| 7 | 7 | |
| 8 | 8 | #include <drm/xe_drm.h> |
| 9 | 9 | |
| 10 | +#include <generated/xe_wa_oob.h> | |
| 11 | + | |
| 10 | 12 | #include "regs/xe_reg_defs.h" |
| 11 | 13 | #include "xe_assert.h" |
| 12 | 14 | #include "xe_device.h" |
| @@ -15,6 +17,7 @@ · 2 unmodified lines | ||
| 15 | 17 | #include "xe_gt_mcr.h" |
| 16 | 18 | #include "xe_mmio.h" |
| 17 | 19 | #include "xe_sriov.h" |
| 20 | +#include "xe_wa.h" | |
| 18 | 21 | |
| 19 | 22 | #define _PAT_ATS 0x47fc |
| 20 | 23 | #define _PAT_INDEX(index) _PICK_EVEN_2RANGES(index, 8, \ |
| @@ -382,7 +385,13 @@ void xe_pat_init_early(struct xe_device *xe) · 361 unmodified lines | ||
| 382 | 385 | if (GRAPHICS_VER(xe) == 20) { |
| 383 | 386 | xe->pat.ops = &xe2_pat_ops; |
| 384 | 387 | xe->pat.table = xe2_pat_table; |
| 385 | − xe->pat.n_entries = ARRAY_SIZE(xe2_pat_table); | |
| 388 | + | |
| 389 | + /* Wa_16023588340. XXX: Should use XE_WA */ | |
| 390 | + if (GRAPHICS_VERx100(xe) == 2001) | |
| 391 | + xe->pat.n_entries = 28; /* Disable CLOS3 */ | |
| 392 | + else | |
| 393 | + xe->pat.n_entries = ARRAY_SIZE(xe2_pat_table); | |
| 394 | + | |
| 386 | 395 | xe->pat.idx[XE_CACHE_NONE] = 3; |
| 387 | 396 | xe->pat.idx[XE_CACHE_WT] = 15; |
| 388 | 397 | xe->pat.idx[XE_CACHE_WB] = 2; |
| @@ -59,6 +59,7 @@ struct xe_device_desc { · 58 unmodified lines | ||
| 59 | 59 | |
| 60 | 60 | u8 has_display:1; |
| 61 | 61 | u8 has_heci_gscfi:1; |
| 62 | + u8 has_heci_cscfi:1; | |
| 62 | 63 | u8 has_llc:1; |
| 63 | 64 | u8 has_mmio_ext:1; |
| 64 | 65 | u8 has_sriov:1; |
| @@ -345,6 +346,7 @@ static const struct xe_device_desc bmg_desc = { · 280 unmodified lines | ||
| 345 | 346 | PLATFORM(BATTLEMAGE), |
| 346 | 347 | .has_display = true, |
| 347 | 348 | .require_force_probe = true, |
| 349 | + .has_heci_cscfi = 1, | |
| 348 | 350 | }; |
| 349 | 351 | |
| 350 | 352 | #undef PLATFORM |
| @@ -606,6 +608,7 @@ static int xe_info_init_early(struct xe_device *xe, · 255 unmodified lines | ||
| 606 | 608 | |
| 607 | 609 | xe->info.is_dgfx = desc->is_dgfx; |
| 608 | 610 | xe->info.has_heci_gscfi = desc->has_heci_gscfi; |
| 611 | + xe->info.has_heci_cscfi = desc->has_heci_cscfi; | |
| 609 | 612 | xe->info.has_llc = desc->has_llc; |
| 610 | 613 | xe->info.has_mmio_ext = desc->has_mmio_ext; |
| 611 | 614 | xe->info.has_sriov = desc->has_sriov; |
| @@ -815,7 +818,7 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 203 unmodified lines | ||
| 815 | 818 | if (err) |
| 816 | 819 | return err; |
| 817 | 820 | |
| 818 | − drm_dbg(&xe->drm, "%s %s %04x:%04x dgfx:%d gfx:%s (%d.%02d) media:%s (%d.%02d) display:%s dma_m_s:%d tc:%d gscfi:%d", | |
| 821 | + drm_dbg(&xe->drm, "%s %s %04x:%04x dgfx:%d gfx:%s (%d.%02d) media:%s (%d.%02d) display:%s dma_m_s:%d tc:%d gscfi:%d cscfi:%d", | |
| 819 | 822 | desc->platform_name, |
| 820 | 823 | subplatform_desc ? subplatform_desc->name : "", |
| 821 | 824 | xe->info.devid, xe->info.revid, |
| @@ -828,7 +831,7 @@ static int xe_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent) · 6 unmodified lines | ||
| 828 | 831 | xe->info.media_verx100 % 100, |
| 829 | 832 | str_yes_no(xe->info.enable_display), |
| 830 | 833 | xe->info.dma_mask_size, xe->info.tile_count, |
| 831 | − xe->info.has_heci_gscfi); | |
| 834 | + xe->info.has_heci_gscfi, xe->info.has_heci_cscfi); | |
| 832 | 835 | |
| 833 | 836 | drm_dbg(&xe->drm, "Stepping = (G:%s, M:%s, D:%s, B:%s)\n", |
| 834 | 837 | xe_step_name(xe->info.step.graphics), |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include "xe_guc.h" |
| 21 | 21 | #include "xe_irq.h" |
| 22 | 22 | #include "xe_pcode.h" |
| 23 | +#include "xe_trace.h" | |
| 23 | 24 | #include "xe_wa.h" |
| 24 | 25 | |
| 25 | 26 | /** |
| @@ -87,6 +88,7 @@ int xe_pm_suspend(struct xe_device *xe) · 61 unmodified lines | ||
| 87 | 88 | int err; |
| 88 | 89 | |
| 89 | 90 | drm_dbg(&xe->drm, "Suspending device\n"); |
| 91 | + trace_xe_pm_suspend(xe, __builtin_return_address(0)); | |
| 90 | 92 | |
| 91 | 93 | for_each_gt(gt, xe, id) |
| 92 | 94 | xe_gt_suspend_prepare(gt); |
| @@ -131,6 +133,7 @@ int xe_pm_resume(struct xe_device *xe) · 38 unmodified lines | ||
| 131 | 133 | int err; |
| 132 | 134 | |
| 133 | 135 | drm_dbg(&xe->drm, "Resuming device\n"); |
| 136 | + trace_xe_pm_resume(xe, __builtin_return_address(0)); | |
| 134 | 137 | |
| 135 | 138 | for_each_tile(tile, xe, id) |
| 136 | 139 | xe_wa_apply_tile_workarounds(tile); |
| @@ -326,6 +329,7 @@ int xe_pm_runtime_suspend(struct xe_device *xe) · 189 unmodified lines | ||
| 326 | 329 | u8 id; |
| 327 | 330 | int err = 0; |
| 328 | 331 | |
| 332 | + trace_xe_pm_runtime_suspend(xe, __builtin_return_address(0)); | |
| 329 | 333 | /* Disable access_ongoing asserts and prevent recursive pm calls */ |
| 330 | 334 | xe_pm_write_callback_task(xe, current); |
| 331 | 335 | |
| @@ -399,6 +403,7 @@ int xe_pm_runtime_resume(struct xe_device *xe) · 67 unmodified lines | ||
| 399 | 403 | u8 id; |
| 400 | 404 | int err = 0; |
| 401 | 405 | |
| 406 | + trace_xe_pm_runtime_resume(xe, __builtin_return_address(0)); | |
| 402 | 407 | /* Disable access_ongoing asserts and prevent recursive pm calls */ |
| 403 | 408 | xe_pm_write_callback_task(xe, current); |
| 404 | 409 | |
| @@ -463,6 +468,7 @@ static void pm_runtime_lockdep_prime(void) · 58 unmodified lines | ||
| 463 | 468 | */ |
| 464 | 469 | void xe_pm_runtime_get(struct xe_device *xe) |
| 465 | 470 | { |
| 471 | + trace_xe_pm_runtime_get(xe, __builtin_return_address(0)); | |
| 466 | 472 | pm_runtime_get_noresume(xe->drm.dev); |
| 467 | 473 | |
| 468 | 474 | if (xe_pm_read_callback_task(xe) == current) |
| @@ -478,6 +484,7 @@ void xe_pm_runtime_get(struct xe_device *xe) · 9 unmodified lines | ||
| 478 | 484 | */ |
| 479 | 485 | void xe_pm_runtime_put(struct xe_device *xe) |
| 480 | 486 | { |
| 487 | + trace_xe_pm_runtime_put(xe, __builtin_return_address(0)); | |
| 481 | 488 | if (xe_pm_read_callback_task(xe) == current) { |
| 482 | 489 | pm_runtime_put_noidle(xe->drm.dev); |
| 483 | 490 | } else { |
| @@ -495,6 +502,7 @@ void xe_pm_runtime_put(struct xe_device *xe) · 11 unmodified lines | ||
| 495 | 502 | */ |
| 496 | 503 | int xe_pm_runtime_get_ioctl(struct xe_device *xe) |
| 497 | 504 | { |
| 505 | + trace_xe_pm_runtime_get_ioctl(xe, __builtin_return_address(0)); | |
| 498 | 506 | if (WARN_ON(xe_pm_read_callback_task(xe) == current)) |
| 499 | 507 | return -ELOOP; |
| 500 | 508 | |
| @@ -17,10 +17,16 @@ static void preempt_fence_work_func(struct work_struct *w) · 16 unmodified lines | ||
| 17 | 17 | container_of(w, typeof(*pfence), preempt_work); |
| 18 | 18 | struct xe_exec_queue *q = pfence->q; |
| 19 | 19 | |
| 20 | − if (pfence->error) | |
| 20 | + if (pfence->error) { | |
| 21 | 21 | dma_fence_set_error(&pfence->base, pfence->error); |
| 22 | − else | |
| 23 | − q->ops->suspend_wait(q); | |
| 22 | + } else if (!q->ops->reset_status(q)) { | |
| 23 | + int err = q->ops->suspend_wait(q); | |
| 24 | + | |
| 25 | + if (err) | |
| 26 | + dma_fence_set_error(&pfence->base, err); | |
| 27 | + } else { | |
| 28 | + dma_fence_set_error(&pfence->base, -ENOENT); | |
| 29 | + } | |
| 24 | 30 | |
| 25 | 31 | dma_fence_signal(&pfence->base); |
| 26 | 32 | /* |
| @@ -9,12 +9,15 @@ · 8 unmodified lines | ||
| 9 | 9 | #include "xe_bo.h" |
| 10 | 10 | #include "xe_device.h" |
| 11 | 11 | #include "xe_drm_client.h" |
| 12 | +#include "xe_exec_queue.h" | |
| 12 | 13 | #include "xe_gt.h" |
| 13 | 14 | #include "xe_gt_tlb_invalidation.h" |
| 14 | 15 | #include "xe_migrate.h" |
| 15 | 16 | #include "xe_pt_types.h" |
| 16 | 17 | #include "xe_pt_walk.h" |
| 17 | 18 | #include "xe_res_cursor.h" |
| 19 | +#include "xe_sched_job.h" | |
| 20 | +#include "xe_sync.h" | |
| 18 | 21 | #include "xe_trace.h" |
| 19 | 22 | #include "xe_ttm_stolen_mgr.h" |
| 20 | 23 | #include "xe_vm.h" |
| @@ -325,6 +328,7 @@ xe_pt_new_shared(struct xe_walk_update *wupd, struct xe_pt *parent, · 304 unmodified lines | ||
| 325 | 328 | entry->pt = parent; |
| 326 | 329 | entry->flags = 0; |
| 327 | 330 | entry->qwords = 0; |
| 331 | + entry->pt_bo->update_index = -1; | |
| 328 | 332 | |
| 329 | 333 | if (alloc_entries) { |
| 330 | 334 | entry->pt_entries = kmalloc_array(XE_PDES, |
| @@ -842,19 +846,27 @@ xe_vm_populate_pgtable(struct xe_migrate_pt_update *pt_update, struct xe_tile *t · 511 unmodified lines | ||
| 842 | 846 | } |
| 843 | 847 | } |
| 844 | 848 | |
| 845 | −static void xe_pt_abort_bind(struct xe_vma *vma, | |
| 846 | − struct xe_vm_pgtable_update *entries, | |
| 847 | − u32 num_entries) | |
| 849 | +static void xe_pt_cancel_bind(struct xe_vma *vma, | |
| 850 | + struct xe_vm_pgtable_update *entries, | |
| 851 | + u32 num_entries) | |
| 848 | 852 | { |
| 849 | 853 | u32 i, j; |
| 850 | 854 | |
| 851 | 855 | for (i = 0; i < num_entries; i++) { |
| 852 | − if (!entries[i].pt_entries) | |
| 856 | + struct xe_pt *pt = entries[i].pt; | |
| 857 | + | |
| 858 | + if (!pt) | |
| 853 | 859 | continue; |
| 854 | 860 | |
| 855 | − for (j = 0; j < entries[i].qwords; j++) | |
| 856 | − xe_pt_destroy(entries[i].pt_entries[j].pt, xe_vma_vm(vma)->flags, NULL); | |
| 861 | + if (pt->level) { | |
| 862 | + for (j = 0; j < entries[i].qwords; j++) | |
| 863 | + xe_pt_destroy(entries[i].pt_entries[j].pt, | |
| 864 | + xe_vma_vm(vma)->flags, NULL); | |
| 865 | + } | |
| 866 | + | |
| 857 | 867 | kfree(entries[i].pt_entries); |
| 868 | + entries[i].pt_entries = NULL; | |
| 869 | + entries[i].qwords = 0; | |
| 858 | 870 | } |
| 859 | 871 | } |
| 860 | 872 | |
| @@ -864,18 +876,15 @@ static void xe_pt_commit_locks_assert(struct xe_vma *vma) · 3 unmodified lines | ||
| 864 | 876 | |
| 865 | 877 | lockdep_assert_held(&vm->lock); |
| 866 | 878 | |
| 867 | − if (xe_vma_is_userptr(vma)) | |
| 868 | − lockdep_assert_held_read(&vm->userptr.notifier_lock); | |
| 869 | − else if (!xe_vma_is_null(vma)) | |
| 879 | + if (!xe_vma_is_userptr(vma) && !xe_vma_is_null(vma)) | |
| 870 | 880 | dma_resv_assert_held(xe_vma_bo(vma)->ttm.base.resv); |
| 871 | 881 | |
| 872 | 882 | xe_vm_assert_held(vm); |
| 873 | 883 | } |
| 874 | 884 | |
| 875 | −static void xe_pt_commit_bind(struct xe_vma *vma, | |
| 876 | − struct xe_vm_pgtable_update *entries, | |
| 877 | − u32 num_entries, bool rebind, | |
| 878 | − struct llist_head *deferred) | |
| 885 | +static void xe_pt_commit(struct xe_vma *vma, | |
| 886 | + struct xe_vm_pgtable_update *entries, | |
| 887 | + u32 num_entries, struct llist_head *deferred) | |
| 879 | 888 | { |
| 880 | 889 | u32 i, j; |
| 881 | 890 | |
| @@ -883,31 +892,90 @@ static void xe_pt_commit_bind(struct xe_vma *vma, · 1 unmodified line | ||
| 883 | 892 | |
| 884 | 893 | for (i = 0; i < num_entries; i++) { |
| 885 | 894 | struct xe_pt *pt = entries[i].pt; |
| 895 | + | |
| 896 | + if (!pt->level) | |
| 897 | + continue; | |
| 898 | + | |
| 899 | + for (j = 0; j < entries[i].qwords; j++) { | |
| 900 | + struct xe_pt *oldpte = entries[i].pt_entries[j].pt; | |
| 901 | + | |
| 902 | + xe_pt_destroy(oldpte, xe_vma_vm(vma)->flags, deferred); | |
| 903 | + } | |
| 904 | + } | |
| 905 | +} | |
| 906 | + | |
| 907 | +static void xe_pt_abort_bind(struct xe_vma *vma, | |
| 908 | + struct xe_vm_pgtable_update *entries, | |
| 909 | + u32 num_entries, bool rebind) | |
| 910 | +{ | |
| 911 | + int i, j; | |
| 912 | + | |
| 913 | + xe_pt_commit_locks_assert(vma); | |
| 914 | + | |
| 915 | + for (i = num_entries - 1; i >= 0; --i) { | |
| 916 | + struct xe_pt *pt = entries[i].pt; | |
| 886 | 917 | struct xe_pt_dir *pt_dir; |
| 887 | 918 | |
| 888 | 919 | if (!rebind) |
| 889 | − pt->num_live += entries[i].qwords; | |
| 920 | + pt->num_live -= entries[i].qwords; | |
| 890 | 921 | |
| 891 | − if (!pt->level) { | |
| 892 | − kfree(entries[i].pt_entries); | |
| 922 | + if (!pt->level) | |
| 893 | 923 | continue; |
| 924 | + | |
| 925 | + pt_dir = as_xe_pt_dir(pt); | |
| 926 | + for (j = 0; j < entries[i].qwords; j++) { | |
| 927 | + u32 j_ = j + entries[i].ofs; | |
| 928 | + struct xe_pt *newpte = xe_pt_entry(pt_dir, j_); | |
| 929 | + struct xe_pt *oldpte = entries[i].pt_entries[j].pt; | |
| 930 | + | |
| 931 | + pt_dir->children[j_] = oldpte ? &oldpte->base : 0; | |
| 932 | + xe_pt_destroy(newpte, xe_vma_vm(vma)->flags, NULL); | |
| 894 | 933 | } |
| 934 | + } | |
| 935 | +} | |
| 936 | + | |
| 937 | +static void xe_pt_commit_prepare_bind(struct xe_vma *vma, | |
| 938 | + struct xe_vm_pgtable_update *entries, | |
| 939 | + u32 num_entries, bool rebind) | |
| 940 | +{ | |
| 941 | + u32 i, j; | |
| 942 | + | |
| 943 | + xe_pt_commit_locks_assert(vma); | |
| 944 | + | |
| 945 | + for (i = 0; i < num_entries; i++) { | |
| 946 | + struct xe_pt *pt = entries[i].pt; | |
| 947 | + struct xe_pt_dir *pt_dir; | |
| 948 | + | |
| 949 | + if (!rebind) | |
| 950 | + pt->num_live += entries[i].qwords; | |
| 951 | + | |
| 952 | + if (!pt->level) | |
| 953 | + continue; | |
| 895 | 954 | |
| 896 | 955 | pt_dir = as_xe_pt_dir(pt); |
| 897 | 956 | for (j = 0; j < entries[i].qwords; j++) { |
| 898 | 957 | u32 j_ = j + entries[i].ofs; |
| 899 | 958 | struct xe_pt *newpte = entries[i].pt_entries[j].pt; |
| 959 | + struct xe_pt *oldpte = NULL; | |
| 900 | 960 | |
| 901 | 961 | if (xe_pt_entry(pt_dir, j_)) |
| 902 | − xe_pt_destroy(xe_pt_entry(pt_dir, j_), | |
| 903 | − xe_vma_vm(vma)->flags, deferred); | |
| 962 | + oldpte = xe_pt_entry(pt_dir, j_); | |
| 904 | 963 | |
| 905 | 964 | pt_dir->children[j_] = &newpte->base; |
| 965 | + entries[i].pt_entries[j].pt = oldpte; | |
| 906 | 966 | } |
| 907 | − kfree(entries[i].pt_entries); | |
| 908 | 967 | } |
| 909 | 968 | } |
| 910 | 969 | |
| 970 | +static void xe_pt_free_bind(struct xe_vm_pgtable_update *entries, | |
| 971 | + u32 num_entries) | |
| 972 | +{ | |
| 973 | + u32 i; | |
| 974 | + | |
| 975 | + for (i = 0; i < num_entries; i++) | |
| 976 | + kfree(entries[i].pt_entries); | |
| 977 | +} | |
| 978 | + | |
| 911 | 979 | static int |
| 912 | 980 | xe_pt_prepare_bind(struct xe_tile *tile, struct xe_vma *vma, |
| 913 | 981 | struct xe_vm_pgtable_update *entries, u32 *num_entries) |
| @@ -918,20 +986,19 @@ xe_pt_prepare_bind(struct xe_tile *tile, struct xe_vma *vma, · 4 unmodified lines | ||
| 918 | 986 | err = xe_pt_stage_bind(tile, vma, entries, num_entries); |
| 919 | 987 | if (!err) |
| 920 | 988 | xe_tile_assert(tile, *num_entries); |
| 921 | − else /* abort! */ | |
| 922 | − xe_pt_abort_bind(vma, entries, *num_entries); | |
| 923 | 989 | |
| 924 | 990 | return err; |
| 925 | 991 | } |
| 926 | 992 | |
| 927 | 993 | static void xe_vm_dbg_print_entries(struct xe_device *xe, |
| 928 | 994 | const struct xe_vm_pgtable_update *entries, |
| 929 | − unsigned int num_entries) | |
| 995 | + unsigned int num_entries, bool bind) | |
| 930 | 996 | #if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_VM)) |
| 931 | 997 | { |
| 932 | 998 | unsigned int i; |
| 933 | 999 | |
| 934 | − vm_dbg(&xe->drm, "%u entries to update\n", num_entries); | |
| 1000 | + vm_dbg(&xe->drm, "%s: %u entries to update\n", bind ? "bind" : "unbind", | |
| 1001 | + num_entries); | |
| 935 | 1002 | for (i = 0; i < num_entries; i++) { |
| 936 | 1003 | const struct xe_vm_pgtable_update *entry = &entries[i]; |
| 937 | 1004 | struct xe_pt *xe_pt = entry->pt; |
| @@ -952,66 +1019,108 @@ static void xe_vm_dbg_print_entries(struct xe_device *xe, · 14 unmodified lines | ||
| 952 | 1019 | {} |
| 953 | 1020 | #endif |
| 954 | 1021 | |
| 955 | −#ifdef CONFIG_DRM_XE_USERPTR_INVAL_INJECT | |
| 956 | − | |
| 957 | −static int xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma) | |
| 1022 | +static bool no_in_syncs(struct xe_sync_entry *syncs, u32 num_syncs) | |
| 958 | 1023 | { |
| 959 | − u32 divisor = uvma->userptr.divisor ? uvma->userptr.divisor : 2; | |
| 960 | − static u32 count; | |
| 1024 | + int i; | |
| 961 | 1025 | |
| 962 | − if (count++ % divisor == divisor - 1) { | |
| 963 | − struct xe_vm *vm = xe_vma_vm(&uvma->vma); | |
| 1026 | + for (i = 0; i < num_syncs; i++) { | |
| 1027 | + struct dma_fence *fence = syncs[i].fence; | |
| 964 | 1028 | |
| 965 | − uvma->userptr.divisor = divisor << 1; | |
| 966 | − spin_lock(&vm->userptr.invalidated_lock); | |
| 967 | − list_move_tail(&uvma->userptr.invalidate_link, | |
| 968 | − &vm->userptr.invalidated); | |
| 969 | − spin_unlock(&vm->userptr.invalidated_lock); | |
| 970 | − return true; | |
| 1029 | + if (fence && !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, | |
| 1030 | + &fence->flags)) | |
| 1031 | + return false; | |
| 971 | 1032 | } |
| 972 | 1033 | |
| 973 | − return false; | |
| 1034 | + return true; | |
| 974 | 1035 | } |
| 975 | 1036 | |
| 976 | −#else | |
| 1037 | +static int job_test_add_deps(struct xe_sched_job *job, | |
| 1038 | + struct dma_resv *resv, | |
| 1039 | + enum dma_resv_usage usage) | |
| 1040 | +{ | |
| 1041 | + if (!job) { | |
| 1042 | + if (!dma_resv_test_signaled(resv, usage)) | |
| 1043 | + return -ETIME; | |
| 977 | 1044 | |
| 978 | −static bool xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma) | |
| 1045 | + return 0; | |
| 1046 | + } | |
| 1047 | + | |
| 1048 | + return xe_sched_job_add_deps(job, resv, usage); | |
| 1049 | +} | |
| 1050 | + | |
| 1051 | +static int vma_add_deps(struct xe_vma *vma, struct xe_sched_job *job) | |
| 979 | 1052 | { |
| 980 | − return false; | |
| 1053 | + struct xe_bo *bo = xe_vma_bo(vma); | |
| 1054 | + | |
| 1055 | + xe_bo_assert_held(bo); | |
| 1056 | + | |
| 1057 | + if (bo && !bo->vm) | |
| 1058 | + return job_test_add_deps(job, bo->ttm.base.resv, | |
| 1059 | + DMA_RESV_USAGE_KERNEL); | |
| 1060 | + | |
| 1061 | + return 0; | |
| 981 | 1062 | } |
| 982 | 1063 | |
| 983 | −#endif | |
| 1064 | +static int op_add_deps(struct xe_vm *vm, struct xe_vma_op *op, | |
| 1065 | + struct xe_sched_job *job) | |
| 1066 | +{ | |
| 1067 | + int err = 0; | |
| 984 | 1068 | |
| 985 | −/** | |
| 986 | − * struct xe_pt_migrate_pt_update - Callback argument for pre-commit callbacks | |
| 987 | − * @base: Base we derive from. | |
| 988 | − * @bind: Whether this is a bind or an unbind operation. A bind operation | |
| 989 | − * makes the pre-commit callback error with -EAGAIN if it detects a | |
| 990 | − * pending invalidation. | |
| 991 | − * @locked: Whether the pre-commit callback locked the userptr notifier lock | |
| 992 | − * and it needs unlocking. | |
| 993 | − */ | |
| 994 | −struct xe_pt_migrate_pt_update { | |
| 995 | − struct xe_migrate_pt_update base; | |
| 996 | − bool bind; | |
| 997 | − bool locked; | |
| 998 | −}; | |
| 1069 | + switch (op->base.op) { | |
| 1070 | + case DRM_GPUVA_OP_MAP: | |
| 1071 | + if (!op->map.immediate && xe_vm_in_fault_mode(vm)) | |
| 1072 | + break; | |
| 1073 | + | |
| 1074 | + err = vma_add_deps(op->map.vma, job); | |
| 1075 | + break; | |
| 1076 | + case DRM_GPUVA_OP_REMAP: | |
| 1077 | + if (op->remap.prev) | |
| 1078 | + err = vma_add_deps(op->remap.prev, job); | |
| 1079 | + if (!err && op->remap.next) | |
| 1080 | + err = vma_add_deps(op->remap.next, job); | |
| 1081 | + break; | |
| 1082 | + case DRM_GPUVA_OP_UNMAP: | |
| 1083 | + break; | |
| 1084 | + case DRM_GPUVA_OP_PREFETCH: | |
| 1085 | + err = vma_add_deps(gpuva_to_vma(op->base.prefetch.va), job); | |
| 1086 | + break; | |
| 1087 | + default: | |
| 1088 | + drm_warn(&vm->xe->drm, "NOT POSSIBLE"); | |
| 1089 | + } | |
| 1090 | + | |
| 1091 | + return err; | |
| 1092 | +} | |
| 999 | 1093 | |
| 1000 | −/* | |
| 1001 | − * This function adds the needed dependencies to a page-table update job | |
| 1002 | − * to make sure racing jobs for separate bind engines don't race writing | |
| 1003 | − * to the same page-table range, wreaking havoc. Initially use a single | |
| 1004 | − * fence for the entire VM. An optimization would use smaller granularity. | |
| 1005 | − */ | |
| 1006 | 1094 | static int xe_pt_vm_dependencies(struct xe_sched_job *job, |
| 1007 | − struct xe_range_fence_tree *rftree, | |
| 1008 | − u64 start, u64 last) | |
| 1095 | + struct xe_vm *vm, | |
| 1096 | + struct xe_vma_ops *vops, | |
| 1097 | + struct xe_vm_pgtable_update_ops *pt_update_ops, | |
| 1098 | + struct xe_range_fence_tree *rftree) | |
| 1009 | 1099 | { |
| 1010 | 1100 | struct xe_range_fence *rtfence; |
| 1011 | 1101 | struct dma_fence *fence; |
| 1012 | − int err; | |
| 1102 | + struct xe_vma_op *op; | |
| 1103 | + int err = 0, i; | |
| 1104 | + | |
| 1105 | + xe_vm_assert_held(vm); | |
| 1013 | 1106 | |
| 1014 | − rtfence = xe_range_fence_tree_first(rftree, start, last); | |
| 1107 | + if (!job && !no_in_syncs(vops->syncs, vops->num_syncs)) | |
| 1108 | + return -ETIME; | |
| 1109 | + | |
| 1110 | + if (!job && !xe_exec_queue_is_idle(pt_update_ops->q)) | |
| 1111 | + return -ETIME; | |
| 1112 | + | |
| 1113 | + if (pt_update_ops->wait_vm_bookkeep || pt_update_ops->wait_vm_kernel) { | |
| 1114 | + err = job_test_add_deps(job, xe_vm_resv(vm), | |
| 1115 | + pt_update_ops->wait_vm_bookkeep ? | |
| 1116 | + DMA_RESV_USAGE_BOOKKEEP : | |
| 1117 | + DMA_RESV_USAGE_KERNEL); | |
| 1118 | + if (err) | |
| 1119 | + return err; | |
| 1120 | + } | |
| 1121 | + | |
| 1122 | + rtfence = xe_range_fence_tree_first(rftree, pt_update_ops->start, | |
| 1123 | + pt_update_ops->last); | |
| 1015 | 1124 | while (rtfence) { |
| 1016 | 1125 | fence = rtfence->fence; |
| 1017 | 1126 | |
| @@ -1029,80 +1138,173 @@ static int xe_pt_vm_dependencies(struct xe_sched_job *job, · 11 unmodified lines | ||
| 1029 | 1138 | return err; |
| 1030 | 1139 | } |
| 1031 | 1140 | |
| 1032 | − rtfence = xe_range_fence_tree_next(rtfence, start, last); | |
| 1141 | + rtfence = xe_range_fence_tree_next(rtfence, | |
| 1142 | + pt_update_ops->start, | |
| 1143 | + pt_update_ops->last); | |
| 1033 | 1144 | } |
| 1034 | 1145 | |
| 1035 | − return 0; | |
| 1146 | + list_for_each_entry(op, &vops->list, link) { | |
| 1147 | + err = op_add_deps(vm, op, job); | |
| 1148 | + if (err) | |
| 1149 | + return err; | |
| 1150 | + } | |
| 1151 | + | |
| 1152 | + if (job) | |
| 1153 | + err = xe_sched_job_last_fence_add_dep(job, vm); | |
| 1154 | + else | |
| 1155 | + err = xe_exec_queue_last_fence_test_dep(pt_update_ops->q, vm); | |
| 1156 | + | |
| 1157 | + for (i = 0; job && !err && i < vops->num_syncs; i++) | |
| 1158 | + err = xe_sync_entry_add_deps(&vops->syncs[i], job); | |
| 1159 | + | |
| 1160 | + return err; | |
| 1036 | 1161 | } |
| 1037 | 1162 | |
| 1038 | 1163 | static int xe_pt_pre_commit(struct xe_migrate_pt_update *pt_update) |
| 1039 | 1164 | { |
| 1040 | − struct xe_range_fence_tree *rftree = | |
| 1041 | − &xe_vma_vm(pt_update->vma)->rftree[pt_update->tile_id]; | |
| 1165 | + struct xe_vma_ops *vops = pt_update->vops; | |
| 1166 | + struct xe_vm *vm = vops->vm; | |
| 1167 | + struct xe_range_fence_tree *rftree = &vm->rftree[pt_update->tile_id]; | |
| 1168 | + struct xe_vm_pgtable_update_ops *pt_update_ops = | |
| 1169 | + &vops->pt_update_ops[pt_update->tile_id]; | |
| 1170 | + | |
| 1171 | + return xe_pt_vm_dependencies(pt_update->job, vm, pt_update->vops, | |
| 1172 | + pt_update_ops, rftree); | |
| 1173 | +} | |
| 1042 | 1174 | |
| 1043 | − return xe_pt_vm_dependencies(pt_update->job, rftree, | |
| 1044 | − pt_update->start, pt_update->last); | |
| 1175 | +#ifdef CONFIG_DRM_XE_USERPTR_INVAL_INJECT | |
| 1176 | + | |
| 1177 | +static bool xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma) | |
| 1178 | +{ | |
| 1179 | + u32 divisor = uvma->userptr.divisor ? uvma->userptr.divisor : 2; | |
| 1180 | + static u32 count; | |
| 1181 | + | |
| 1182 | + if (count++ % divisor == divisor - 1) { | |
| 1183 | + uvma->userptr.divisor = divisor << 1; | |
| 1184 | + return true; | |
| 1185 | + } | |
| 1186 | + | |
| 1187 | + return false; | |
| 1045 | 1188 | } |
| 1046 | 1189 | |
| 1047 | −static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update) | |
| 1190 | +#else | |
| 1191 | + | |
| 1192 | +static bool xe_pt_userptr_inject_eagain(struct xe_userptr_vma *uvma) | |
| 1048 | 1193 | { |
| 1049 | − struct xe_pt_migrate_pt_update *userptr_update = | |
| 1050 | − container_of(pt_update, typeof(*userptr_update), base); | |
| 1051 | − struct xe_userptr_vma *uvma = to_userptr_vma(pt_update->vma); | |
| 1052 | − unsigned long notifier_seq = uvma->userptr.notifier_seq; | |
| 1053 | − struct xe_vm *vm = xe_vma_vm(&uvma->vma); | |
| 1054 | − int err = xe_pt_vm_dependencies(pt_update->job, | |
| 1055 | − &vm->rftree[pt_update->tile_id], | |
| 1056 | − pt_update->start, | |
| 1057 | − pt_update->last); | |
| 1194 | + return false; | |
| 1195 | +} | |
| 1058 | 1196 | |
| 1059 | − if (err) | |
| 1060 | − return err; | |
| 1197 | +#endif | |
| 1061 | 1198 | |
| 1062 | − userptr_update->locked = false; | |
| 1199 | +static int vma_check_userptr(struct xe_vm *vm, struct xe_vma *vma, | |
| 1200 | + struct xe_vm_pgtable_update_ops *pt_update) | |
| 1201 | +{ | |
| 1202 | + struct xe_userptr_vma *uvma; | |
| 1203 | + unsigned long notifier_seq; | |
| 1063 | 1204 | |
| 1064 | − /* | |
| 1065 | − * Wait until nobody is running the invalidation notifier, and | |
| 1066 | − * since we're exiting the loop holding the notifier lock, | |
| 1067 | − * nobody can proceed invalidating either. | |
| 1068 | − * | |
| 1069 | − * Note that we don't update the vma->userptr.notifier_seq since | |
| 1070 | − * we don't update the userptr pages. | |
| 1071 | − */ | |
| 1072 | − do { | |
| 1073 | − down_read(&vm->userptr.notifier_lock); | |
| 1074 | − if (!mmu_interval_read_retry(&uvma->userptr.notifier, | |
| 1075 | − notifier_seq)) | |
| 1076 | − break; | |
| 1205 | + lockdep_assert_held_read(&vm->userptr.notifier_lock); | |
| 1077 | 1206 | |
| 1078 | − up_read(&vm->userptr.notifier_lock); | |
| 1207 | + if (!xe_vma_is_userptr(vma)) | |
| 1208 | + return 0; | |
| 1079 | 1209 | |
| 1080 | − if (userptr_update->bind) | |
| 1081 | − return -EAGAIN; | |
| 1210 | + uvma = to_userptr_vma(vma); | |
| 1211 | + notifier_seq = uvma->userptr.notifier_seq; | |
| 1082 | 1212 | |
| 1083 | − notifier_seq = mmu_interval_read_begin(&uvma->userptr.notifier); | |
| 1084 | − } while (true); | |
| 1213 | + if (uvma->userptr.initial_bind && !xe_vm_in_fault_mode(vm)) | |
| 1214 | + return 0; | |
| 1085 | 1215 | |
| 1086 | − /* Inject errors to test_whether they are handled correctly */ | |
| 1087 | − if (userptr_update->bind && xe_pt_userptr_inject_eagain(uvma)) { | |
| 1088 | − up_read(&vm->userptr.notifier_lock); | |
| 1216 | + if (!mmu_interval_read_retry(&uvma->userptr.notifier, | |
| 1217 | + notifier_seq) && | |
| 1218 | + !xe_pt_userptr_inject_eagain(uvma)) | |
| 1219 | + return 0; | |
| 1220 | + | |
| 1221 | + if (xe_vm_in_fault_mode(vm)) { | |
| 1089 | 1222 | return -EAGAIN; |
| 1090 | − } | |
| 1223 | + } else { | |
| 1224 | + spin_lock(&vm->userptr.invalidated_lock); | |
| 1225 | + list_move_tail(&uvma->userptr.invalidate_link, | |
| 1226 | + &vm->userptr.invalidated); | |
| 1227 | + spin_unlock(&vm->userptr.invalidated_lock); | |
| 1091 | 1228 | |
| 1092 | − userptr_update->locked = true; | |
| 1229 | + if (xe_vm_in_preempt_fence_mode(vm)) { | |
| 1230 | + struct dma_resv_iter cursor; | |
| 1231 | + struct dma_fence *fence; | |
| 1232 | + long err; | |
| 1233 | + | |
| 1234 | + dma_resv_iter_begin(&cursor, xe_vm_resv(vm), | |
| 1235 | + DMA_RESV_USAGE_BOOKKEEP); | |
| 1236 | + dma_resv_for_each_fence_unlocked(&cursor, fence) | |
| 1237 | + dma_fence_enable_sw_signaling(fence); | |
| 1238 | + dma_resv_iter_end(&cursor); | |
| 1239 | + | |
| 1240 | + err = dma_resv_wait_timeout(xe_vm_resv(vm), | |
| 1241 | + DMA_RESV_USAGE_BOOKKEEP, | |
| 1242 | + false, MAX_SCHEDULE_TIMEOUT); | |
| 1243 | + XE_WARN_ON(err <= 0); | |
| 1244 | + } | |
| 1245 | + } | |
| 1093 | 1246 | |
| 1094 | 1247 | return 0; |
| 1095 | 1248 | } |
| 1096 | 1249 | |
| 1097 | −static const struct xe_migrate_pt_update_ops bind_ops = { | |
| 1098 | − .populate = xe_vm_populate_pgtable, | |
| 1099 | − .pre_commit = xe_pt_pre_commit, | |
| 1100 | −}; | |
| 1250 | +static int op_check_userptr(struct xe_vm *vm, struct xe_vma_op *op, | |
| 1251 | + struct xe_vm_pgtable_update_ops *pt_update) | |
| 1252 | +{ | |
| 1253 | + int err = 0; | |
| 1101 | 1254 | |
| 1102 | −static const struct xe_migrate_pt_update_ops userptr_bind_ops = { | |
| 1103 | − .populate = xe_vm_populate_pgtable, | |
| 1104 | − .pre_commit = xe_pt_userptr_pre_commit, | |
| 1105 | −}; | |
| 1255 | + lockdep_assert_held_read(&vm->userptr.notifier_lock); | |
| 1256 | + | |
| 1257 | + switch (op->base.op) { | |
| 1258 | + case DRM_GPUVA_OP_MAP: | |
| 1259 | + if (!op->map.immediate && xe_vm_in_fault_mode(vm)) | |
| 1260 | + break; | |
| 1261 | + | |
| 1262 | + err = vma_check_userptr(vm, op->map.vma, pt_update); | |
| 1263 | + break; | |
| 1264 | + case DRM_GPUVA_OP_REMAP: | |
| 1265 | + if (op->remap.prev) | |
| 1266 | + err = vma_check_userptr(vm, op->remap.prev, pt_update); | |
| 1267 | + if (!err && op->remap.next) | |
| 1268 | + err = vma_check_userptr(vm, op->remap.next, pt_update); | |
| 1269 | + break; | |
| 1270 | + case DRM_GPUVA_OP_UNMAP: | |
| 1271 | + break; | |
| 1272 | + case DRM_GPUVA_OP_PREFETCH: | |
| 1273 | + err = vma_check_userptr(vm, gpuva_to_vma(op->base.prefetch.va), | |
| 1274 | + pt_update); | |
| 1275 | + break; | |
| 1276 | + default: | |
| 1277 | + drm_warn(&vm->xe->drm, "NOT POSSIBLE"); | |
| 1278 | + } | |
| 1279 | + | |
| 1280 | + return err; | |
| 1281 | +} | |
| 1282 | + | |
| 1283 | +static int xe_pt_userptr_pre_commit(struct xe_migrate_pt_update *pt_update) | |
| 1284 | +{ | |
| 1285 | + struct xe_vm *vm = pt_update->vops->vm; | |
| 1286 | + struct xe_vma_ops *vops = pt_update->vops; | |
| 1287 | + struct xe_vm_pgtable_update_ops *pt_update_ops = | |
| 1288 | + &vops->pt_update_ops[pt_update->tile_id]; | |
| 1289 | + struct xe_vma_op *op; | |
| 1290 | + int err; | |
| 1291 | + | |
| 1292 | + err = xe_pt_pre_commit(pt_update); | |
| 1293 | + if (err) | |
| 1294 | + return err; | |
| 1295 | + | |
| 1296 | + down_read(&vm->userptr.notifier_lock); | |
| 1297 | + | |
| 1298 | + list_for_each_entry(op, &vops->list, link) { | |
| 1299 | + err = op_check_userptr(vm, op, pt_update_ops); | |
| 1300 | + if (err) { | |
| 1301 | + up_read(&vm->userptr.notifier_lock); | |
| 1302 | + break; | |
| 1303 | + } | |
| 1304 | + } | |
| 1305 | + | |
| 1306 | + return err; | |
| 1307 | +} | |
| 1106 | 1308 | |
| 1107 | 1309 | struct invalidation_fence { |
| 1108 | 1310 | struct xe_gt_tlb_invalidation_fence base; |
| @@ -1115,23 +1317,6 @@ struct invalidation_fence { · 6 unmodified lines | ||
| 1115 | 1317 | u32 asid; |
| 1116 | 1318 | }; |
| 1117 | 1319 | |
| 1118 | −static const char * | |
| 1119 | −invalidation_fence_get_driver_name(struct dma_fence *dma_fence) | |
| 1120 | −{ | |
| 1121 | − return "xe"; | |
| 1122 | −} | |
| 1123 | − | |
| 1124 | −static const char * | |
| 1125 | −invalidation_fence_get_timeline_name(struct dma_fence *dma_fence) | |
| 1126 | −{ | |
| 1127 | − return "invalidation_fence"; | |
| 1128 | −} | |
| 1129 | − | |
| 1130 | −static const struct dma_fence_ops invalidation_fence_ops = { | |
| 1131 | − .get_driver_name = invalidation_fence_get_driver_name, | |
| 1132 | − .get_timeline_name = invalidation_fence_get_timeline_name, | |
| 1133 | −}; | |
| 1134 | − | |
| 1135 | 1320 | static void invalidation_fence_cb(struct dma_fence *fence, |
| 1136 | 1321 | struct dma_fence_cb *cb) |
| 1137 | 1322 | { |
| @@ -1161,24 +1346,17 @@ static void invalidation_fence_work_func(struct work_struct *w) · 23 unmodified lines | ||
| 1161 | 1346 | ifence->end, ifence->asid); |
| 1162 | 1347 | } |
| 1163 | 1348 | |
| 1164 | −static int invalidation_fence_init(struct xe_gt *gt, | |
| 1165 | − struct invalidation_fence *ifence, | |
| 1166 | − struct dma_fence *fence, | |
| 1167 | − u64 start, u64 end, u32 asid) | |
| 1349 | +static void invalidation_fence_init(struct xe_gt *gt, | |
| 1350 | + struct invalidation_fence *ifence, | |
| 1351 | + struct dma_fence *fence, | |
| 1352 | + u64 start, u64 end, u32 asid) | |
| 1168 | 1353 | { |
| 1169 | 1354 | int ret; |
| 1170 | 1355 | |
| 1171 | 1356 | trace_xe_gt_tlb_invalidation_fence_create(gt_to_xe(gt), &ifence->base); |
| 1172 | 1357 | |
| 1173 | − spin_lock_irq(>->tlb_invalidation.lock); | |
| 1174 | − dma_fence_init(&ifence->base.base, &invalidation_fence_ops, | |
| 1175 | − >->tlb_invalidation.lock, | |
| 1176 | − dma_fence_context_alloc(1), 1); | |
| 1177 | − spin_unlock_irq(>->tlb_invalidation.lock); | |
| 1178 | − | |
| 1179 | − INIT_LIST_HEAD(&ifence->base.link); | |
| 1358 | + xe_gt_tlb_invalidation_fence_init(gt, &ifence->base, false); | |
| 1180 | 1359 | |
| 1181 | − dma_fence_get(&ifence->base.base); /* Ref for caller */ | |
| 1182 | 1360 | ifence->fence = fence; |
| 1183 | 1361 | ifence->gt = gt; |
| 1184 | 1362 | ifence->start = start; |
| @@ -1196,192 +1374,6 @@ static int invalidation_fence_init(struct xe_gt *gt, · 11 unmodified lines | ||
| 1196 | 1374 | } |
| 1197 | 1375 | |
| 1198 | 1376 | xe_gt_assert(gt, !ret || ret == -ENOENT); |
| 1199 | − | |
| 1200 | − return ret && ret != -ENOENT ? ret : 0; | |
| 1201 | −} | |
| 1202 | − | |
| 1203 | −static void xe_pt_calc_rfence_interval(struct xe_vma *vma, | |
| 1204 | − struct xe_pt_migrate_pt_update *update, | |
| 1205 | − struct xe_vm_pgtable_update *entries, | |
| 1206 | − u32 num_entries) | |
| 1207 | −{ | |
| 1208 | − int i, level = 0; | |
| 1209 | − | |
| 1210 | − for (i = 0; i < num_entries; i++) { | |
| 1211 | − const struct xe_vm_pgtable_update *entry = &entries[i]; | |
| 1212 | − | |
| 1213 | − if (entry->pt->level > level) | |
| 1214 | − level = entry->pt->level; | |
| 1215 | − } | |
| 1216 | − | |
| 1217 | − /* Greedy (non-optimal) calculation but simple */ | |
| 1218 | − update->base.start = ALIGN_DOWN(xe_vma_start(vma), | |
| 1219 | − 0x1ull << xe_pt_shift(level)); | |
| 1220 | − update->base.last = ALIGN(xe_vma_end(vma), | |
| 1221 | − 0x1ull << xe_pt_shift(level)) - 1; | |
| 1222 | −} | |
| 1223 | − | |
| 1224 | −/** | |
| 1225 | − * __xe_pt_bind_vma() - Build and connect a page-table tree for the vma | |
| 1226 | − * address range. | |
| 1227 | − * @tile: The tile to bind for. | |
| 1228 | − * @vma: The vma to bind. | |
| 1229 | − * @q: The exec_queue with which to do pipelined page-table updates. | |
| 1230 | − * @syncs: Entries to sync on before binding the built tree to the live vm tree. | |
| 1231 | − * @num_syncs: Number of @sync entries. | |
| 1232 | − * @rebind: Whether we're rebinding this vma to the same address range without | |
| 1233 | − * an unbind in-between. | |
| 1234 | − * | |
| 1235 | − * This function builds a page-table tree (see xe_pt_stage_bind() for more | |
| 1236 | − * information on page-table building), and the xe_vm_pgtable_update entries | |
| 1237 | − * abstracting the operations needed to attach it to the main vm tree. It | |
| 1238 | − * then takes the relevant locks and updates the metadata side of the main | |
| 1239 | − * vm tree and submits the operations for pipelined attachment of the | |
| 1240 | − * gpu page-table to the vm main tree, (which can be done either by the | |
| 1241 | − * cpu and the GPU). | |
| 1242 | − * | |
| 1243 | − * Return: A valid dma-fence representing the pipelined attachment operation | |
| 1244 | − * on success, an error pointer on error. | |
| 1245 | − */ | |
| 1246 | −struct dma_fence * | |
| 1247 | −__xe_pt_bind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue *q, | |
| 1248 | − struct xe_sync_entry *syncs, u32 num_syncs, | |
| 1249 | − bool rebind) | |
| 1250 | −{ | |
| 1251 | − struct xe_vm_pgtable_update entries[XE_VM_MAX_LEVEL * 2 + 1]; | |
| 1252 | − struct xe_pt_migrate_pt_update bind_pt_update = { | |
| 1253 | − .base = { | |
| 1254 | − .ops = xe_vma_is_userptr(vma) ? &userptr_bind_ops : &bind_ops, | |
| 1255 | − .vma = vma, | |
| 1256 | − .tile_id = tile->id, | |
| 1257 | − }, | |
| 1258 | − .bind = true, | |
| 1259 | − }; | |
| 1260 | − struct xe_vm *vm = xe_vma_vm(vma); | |
| 1261 | − u32 num_entries; | |
| 1262 | − struct dma_fence *fence; | |
| 1263 | − struct invalidation_fence *ifence = NULL; | |
| 1264 | − struct xe_range_fence *rfence; | |
| 1265 | − int err; | |
| 1266 | − | |
| 1267 | − bind_pt_update.locked = false; | |
| 1268 | − xe_bo_assert_held(xe_vma_bo(vma)); | |
| 1269 | − xe_vm_assert_held(vm); | |
| 1270 | − | |
| 1271 | − vm_dbg(&xe_vma_vm(vma)->xe->drm, | |
| 1272 | − "Preparing bind, with range [%llx...%llx) engine %p.\n", | |
| 1273 | − xe_vma_start(vma), xe_vma_end(vma), q); | |
| 1274 | − | |
| 1275 | − err = xe_pt_prepare_bind(tile, vma, entries, &num_entries); | |
| 1276 | − if (err) | |
| 1277 | − goto err; | |
| 1278 | − | |
| 1279 | − err = dma_resv_reserve_fences(xe_vm_resv(vm), 1); | |
| 1280 | − if (!err && !xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) | |
| 1281 | − err = dma_resv_reserve_fences(xe_vma_bo(vma)->ttm.base.resv, 1); | |
| 1282 | − if (err) | |
| 1283 | − goto err; | |
| 1284 | − | |
| 1285 | − xe_tile_assert(tile, num_entries <= ARRAY_SIZE(entries)); | |
| 1286 | − | |
| 1287 | − xe_vm_dbg_print_entries(tile_to_xe(tile), entries, num_entries); | |
| 1288 | − xe_pt_calc_rfence_interval(vma, &bind_pt_update, entries, | |
| 1289 | − num_entries); | |
| 1290 | − | |
| 1291 | − /* | |
| 1292 | − * If rebind, we have to invalidate TLB on !LR vms to invalidate | |
| 1293 | − * cached PTEs point to freed memory. on LR vms this is done | |
| 1294 | − * automatically when the context is re-enabled by the rebind worker, | |
| 1295 | − * or in fault mode it was invalidated on PTE zapping. | |
| 1296 | − * | |
| 1297 | − * If !rebind, and scratch enabled VMs, there is a chance the scratch | |
| 1298 | − * PTE is already cached in the TLB so it needs to be invalidated. | |
| 1299 | − * on !LR VMs this is done in the ring ops preceding a batch, but on | |
| 1300 | − * non-faulting LR, in particular on user-space batch buffer chaining, | |
| 1301 | − * it needs to be done here. | |
| 1302 | − */ | |
| 1303 | − if ((!rebind && xe_vm_has_scratch(vm) && xe_vm_in_preempt_fence_mode(vm))) { | |
| 1304 | − ifence = kzalloc(sizeof(*ifence), GFP_KERNEL); | |
| 1305 | − if (!ifence) | |
| 1306 | − return ERR_PTR(-ENOMEM); | |
| 1307 | − } else if (rebind && !xe_vm_in_lr_mode(vm)) { | |
| 1308 | − /* We bump also if batch_invalidate_tlb is true */ | |
| 1309 | − vm->tlb_flush_seqno++; | |
| 1310 | − } | |
| 1311 | − | |
| 1312 | − rfence = kzalloc(sizeof(*rfence), GFP_KERNEL); | |
| 1313 | − if (!rfence) { | |
| 1314 | − kfree(ifence); | |
| 1315 | − return ERR_PTR(-ENOMEM); | |
| 1316 | − } | |
| 1317 | − | |
| 1318 | − fence = xe_migrate_update_pgtables(tile->migrate, | |
| 1319 | − vm, xe_vma_bo(vma), q, | |
| 1320 | − entries, num_entries, | |
| 1321 | − syncs, num_syncs, | |
| 1322 | − &bind_pt_update.base); | |
| 1323 | − if (!IS_ERR(fence)) { | |
| 1324 | − bool last_munmap_rebind = vma->gpuva.flags & XE_VMA_LAST_REBIND; | |
| 1325 | − LLIST_HEAD(deferred); | |
| 1326 | − int err; | |
| 1327 | − | |
| 1328 | − err = xe_range_fence_insert(&vm->rftree[tile->id], rfence, | |
| 1329 | − &xe_range_fence_kfree_ops, | |
| 1330 | − bind_pt_update.base.start, | |
| 1331 | − bind_pt_update.base.last, fence); | |
| 1332 | − if (err) | |
| 1333 | − dma_fence_wait(fence, false); | |
| 1334 | − | |
| 1335 | − /* TLB invalidation must be done before signaling rebind */ | |
| 1336 | − if (ifence) { | |
| 1337 | − int err = invalidation_fence_init(tile->primary_gt, | |
| 1338 | − ifence, fence, | |
| 1339 | − xe_vma_start(vma), | |
| 1340 | − xe_vma_end(vma), | |
| 1341 | − xe_vma_vm(vma)->usm.asid); | |
| 1342 | − if (err) { | |
| 1343 | − dma_fence_put(fence); | |
| 1344 | − kfree(ifence); | |
| 1345 | − return ERR_PTR(err); | |
| 1346 | − } | |
| 1347 | − fence = &ifence->base.base; | |
| 1348 | − } | |
| 1349 | − | |
| 1350 | − /* add shared fence now for pagetable delayed destroy */ | |
| 1351 | − dma_resv_add_fence(xe_vm_resv(vm), fence, rebind || | |
| 1352 | − last_munmap_rebind ? | |
| 1353 | − DMA_RESV_USAGE_KERNEL : | |
| 1354 | − DMA_RESV_USAGE_BOOKKEEP); | |
| 1355 | − | |
| 1356 | − if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) | |
| 1357 | − dma_resv_add_fence(xe_vma_bo(vma)->ttm.base.resv, fence, | |
| 1358 | − DMA_RESV_USAGE_BOOKKEEP); | |
| 1359 | − xe_pt_commit_bind(vma, entries, num_entries, rebind, | |
| 1360 | − bind_pt_update.locked ? &deferred : NULL); | |
| 1361 | − | |
| 1362 | − /* This vma is live (again?) now */ | |
| 1363 | − vma->tile_present |= BIT(tile->id); | |
| 1364 | − | |
| 1365 | − if (bind_pt_update.locked) { | |
| 1366 | − to_userptr_vma(vma)->userptr.initial_bind = true; | |
| 1367 | − up_read(&vm->userptr.notifier_lock); | |
| 1368 | − xe_bo_put_commit(&deferred); | |
| 1369 | − } | |
| 1370 | − if (!rebind && last_munmap_rebind && | |
| 1371 | − xe_vm_in_preempt_fence_mode(vm)) | |
| 1372 | − xe_vm_queue_rebind_worker(vm); | |
| 1373 | − } else { | |
| 1374 | − kfree(rfence); | |
| 1375 | − kfree(ifence); | |
| 1376 | − if (bind_pt_update.locked) | |
| 1377 | − up_read(&vm->userptr.notifier_lock); | |
| 1378 | − xe_pt_abort_bind(vma, entries, num_entries); | |
| 1379 | − } | |
| 1380 | − | |
| 1381 | − return fence; | |
| 1382 | − | |
| 1383 | −err: | |
| 1384 | − return ERR_PTR(err); | |
| 1385 | 1377 | } |
| 1386 | 1378 | |
| 1387 | 1379 | struct xe_pt_stage_unbind_walk { |
| @@ -1466,6 +1458,7 @@ xe_pt_stage_unbind_post_descend(struct xe_ptw *parent, pgoff_t offset, · 78 unmodified lines | ||
| 1466 | 1458 | struct xe_pt *xe_child = container_of(*child, typeof(*xe_child), base); |
| 1467 | 1459 | pgoff_t end_offset; |
| 1468 | 1460 | u64 size = 1ull << walk->shifts[--level]; |
| 1461 | + int err; | |
| 1469 | 1462 | |
| 1470 | 1463 | if (!IS_ALIGNED(addr, size)) |
| 1471 | 1464 | addr = xe_walk->modified_start; |
| @@ -1481,7 +1474,10 @@ xe_pt_stage_unbind_post_descend(struct xe_ptw *parent, pgoff_t offset, · 9 unmodified lines | ||
| 1481 | 1474 | &end_offset)) |
| 1482 | 1475 | return 0; |
| 1483 | 1476 | |
| 1484 | − (void)xe_pt_new_shared(&xe_walk->wupd, xe_child, offset, false); | |
| 1477 | + err = xe_pt_new_shared(&xe_walk->wupd, xe_child, offset, true); | |
| 1478 | + if (err) | |
| 1479 | + return err; | |
| 1480 | + | |
| 1485 | 1481 | xe_walk->wupd.updates[level].update->qwords = end_offset - offset; |
| 1486 | 1482 | |
| 1487 | 1483 | return 0; |
| @@ -1534,8 +1530,8 @@ xe_migrate_clear_pgtable_callback(struct xe_migrate_pt_update *pt_update, · 46 unmodified lines | ||
| 1534 | 1530 | void *ptr, u32 qword_ofs, u32 num_qwords, |
| 1535 | 1531 | const struct xe_vm_pgtable_update *update) |
| 1536 | 1532 | { |
| 1537 | − struct xe_vma *vma = pt_update->vma; | |
| 1538 | − u64 empty = __xe_pt_empty_pte(tile, xe_vma_vm(vma), update->pt->level); | |
| 1533 | + struct xe_vm *vm = pt_update->vops->vm; | |
| 1534 | + u64 empty = __xe_pt_empty_pte(tile, vm, update->pt->level); | |
| 1539 | 1535 | int i; |
| 1540 | 1536 | |
| 1541 | 1537 | if (map && map->is_iomem) |
| @@ -1549,181 +1545,571 @@ xe_migrate_clear_pgtable_callback(struct xe_migrate_pt_update *pt_update, · 7 unmodified lines | ||
| 1549 | 1545 | memset64(ptr, empty, num_qwords); |
| 1550 | 1546 | } |
| 1551 | 1547 | |
| 1548 | +static void xe_pt_abort_unbind(struct xe_vma *vma, | |
| 1549 | + struct xe_vm_pgtable_update *entries, | |
| 1550 | + u32 num_entries) | |
| 1551 | +{ | |
| 1552 | + int i, j; | |
| 1553 | + | |
| 1554 | + xe_pt_commit_locks_assert(vma); | |
| 1555 | + | |
| 1556 | + for (i = num_entries - 1; i >= 0; --i) { | |
| 1557 | + struct xe_vm_pgtable_update *entry = &entries[i]; | |
| 1558 | + struct xe_pt *pt = entry->pt; | |
| 1559 | + struct xe_pt_dir *pt_dir = as_xe_pt_dir(pt); | |
| 1560 | + | |
| 1561 | + pt->num_live += entry->qwords; | |
| 1562 | + | |
| 1563 | + if (!pt->level) | |
| 1564 | + continue; | |
| 1565 | + | |
| 1566 | + for (j = entry->ofs; j < entry->ofs + entry->qwords; j++) | |
| 1567 | + pt_dir->children[j] = | |
| 1568 | + entries[i].pt_entries[j - entry->ofs].pt ? | |
| 1569 | + &entries[i].pt_entries[j - entry->ofs].pt->base : NULL; | |
| 1570 | + } | |
| 1571 | +} | |
| 1572 | + | |
| 1552 | 1573 | static void |
| 1553 | −xe_pt_commit_unbind(struct xe_vma *vma, | |
| 1554 | − struct xe_vm_pgtable_update *entries, u32 num_entries, | |
| 1555 | − struct llist_head *deferred) | |
| 1574 | +xe_pt_commit_prepare_unbind(struct xe_vma *vma, | |
| 1575 | + struct xe_vm_pgtable_update *entries, | |
| 1576 | + u32 num_entries) | |
| 1556 | 1577 | { |
| 1557 | − u32 j; | |
| 1578 | + int i, j; | |
| 1558 | 1579 | |
| 1559 | 1580 | xe_pt_commit_locks_assert(vma); |
| 1560 | 1581 | |
| 1561 | − for (j = 0; j < num_entries; ++j) { | |
| 1562 | − struct xe_vm_pgtable_update *entry = &entries[j]; | |
| 1582 | + for (i = 0; i < num_entries; ++i) { | |
| 1583 | + struct xe_vm_pgtable_update *entry = &entries[i]; | |
| 1563 | 1584 | struct xe_pt *pt = entry->pt; |
| 1585 | + struct xe_pt_dir *pt_dir; | |
| 1564 | 1586 | |
| 1565 | 1587 | pt->num_live -= entry->qwords; |
| 1566 | − if (pt->level) { | |
| 1567 | − struct xe_pt_dir *pt_dir = as_xe_pt_dir(pt); | |
| 1568 | − u32 i; | |
| 1588 | + if (!pt->level) | |
| 1589 | + continue; | |
| 1590 | + | |
| 1591 | + pt_dir = as_xe_pt_dir(pt); | |
| 1592 | + for (j = entry->ofs; j < entry->ofs + entry->qwords; j++) { | |
| 1593 | + entry->pt_entries[j - entry->ofs].pt = | |
| 1594 | + xe_pt_entry(pt_dir, j); | |
| 1595 | + pt_dir->children[j] = NULL; | |
| 1596 | + } | |
| 1597 | + } | |
| 1598 | +} | |
| 1599 | + | |
| 1600 | +static void | |
| 1601 | +xe_pt_update_ops_rfence_interval(struct xe_vm_pgtable_update_ops *pt_update_ops, | |
| 1602 | + struct xe_vma *vma) | |
| 1603 | +{ | |
| 1604 | + u32 current_op = pt_update_ops->current_op; | |
| 1605 | + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[current_op]; | |
| 1606 | + int i, level = 0; | |
| 1607 | + u64 start, last; | |
| 1569 | 1608 | |
| 1570 | − for (i = entry->ofs; i < entry->ofs + entry->qwords; | |
| 1571 | − i++) { | |
| 1572 | − if (xe_pt_entry(pt_dir, i)) | |
| 1573 | − xe_pt_destroy(xe_pt_entry(pt_dir, i), | |
| 1574 | − xe_vma_vm(vma)->flags, deferred); | |
| 1609 | + for (i = 0; i < pt_op->num_entries; i++) { | |
| 1610 | + const struct xe_vm_pgtable_update *entry = &pt_op->entries[i]; | |
| 1575 | 1611 | |
| 1576 | − pt_dir->children[i] = NULL; | |
| 1577 | − } | |
| 1612 | + if (entry->pt->level > level) | |
| 1613 | + level = entry->pt->level; | |
| 1614 | + } | |
| 1615 | + | |
| 1616 | + /* Greedy (non-optimal) calculation but simple */ | |
| 1617 | + start = ALIGN_DOWN(xe_vma_start(vma), 0x1ull << xe_pt_shift(level)); | |
| 1618 | + last = ALIGN(xe_vma_end(vma), 0x1ull << xe_pt_shift(level)) - 1; | |
| 1619 | + | |
| 1620 | + if (start < pt_update_ops->start) | |
| 1621 | + pt_update_ops->start = start; | |
| 1622 | + if (last > pt_update_ops->last) | |
| 1623 | + pt_update_ops->last = last; | |
| 1624 | +} | |
| 1625 | + | |
| 1626 | +static int vma_reserve_fences(struct xe_device *xe, struct xe_vma *vma) | |
| 1627 | +{ | |
| 1628 | + if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) | |
| 1629 | + return dma_resv_reserve_fences(xe_vma_bo(vma)->ttm.base.resv, | |
| 1630 | + xe->info.tile_count); | |
| 1631 | + | |
| 1632 | + return 0; | |
| 1633 | +} | |
| 1634 | + | |
| 1635 | +static int bind_op_prepare(struct xe_vm *vm, struct xe_tile *tile, | |
| 1636 | + struct xe_vm_pgtable_update_ops *pt_update_ops, | |
| 1637 | + struct xe_vma *vma) | |
| 1638 | +{ | |
| 1639 | + u32 current_op = pt_update_ops->current_op; | |
| 1640 | + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[current_op]; | |
| 1641 | + int err; | |
| 1642 | + | |
| 1643 | + xe_bo_assert_held(xe_vma_bo(vma)); | |
| 1644 | + | |
| 1645 | + vm_dbg(&xe_vma_vm(vma)->xe->drm, | |
| 1646 | + "Preparing bind, with range [%llx...%llx)\n", | |
| 1647 | + xe_vma_start(vma), xe_vma_end(vma) - 1); | |
| 1648 | + | |
| 1649 | + pt_op->vma = NULL; | |
| 1650 | + pt_op->bind = true; | |
| 1651 | + pt_op->rebind = BIT(tile->id) & vma->tile_present; | |
| 1652 | + | |
| 1653 | + err = vma_reserve_fences(tile_to_xe(tile), vma); | |
| 1654 | + if (err) | |
| 1655 | + return err; | |
| 1656 | + | |
| 1657 | + err = xe_pt_prepare_bind(tile, vma, pt_op->entries, | |
| 1658 | + &pt_op->num_entries); | |
| 1659 | + if (!err) { | |
| 1660 | + xe_tile_assert(tile, pt_op->num_entries <= | |
| 1661 | + ARRAY_SIZE(pt_op->entries)); | |
| 1662 | + xe_vm_dbg_print_entries(tile_to_xe(tile), pt_op->entries, | |
| 1663 | + pt_op->num_entries, true); | |
| 1664 | + | |
| 1665 | + xe_pt_update_ops_rfence_interval(pt_update_ops, vma); | |
| 1666 | + ++pt_update_ops->current_op; | |
| 1667 | + pt_update_ops->needs_userptr_lock |= xe_vma_is_userptr(vma); | |
| 1668 | + | |
| 1669 | + /* | |
| 1670 | + * If rebind, we have to invalidate TLB on !LR vms to invalidate | |
| 1671 | + * cached PTEs point to freed memory. On LR vms this is done | |
| 1672 | + * automatically when the context is re-enabled by the rebind worker, | |
| 1673 | + * or in fault mode it was invalidated on PTE zapping. | |
| 1674 | + * | |
| 1675 | + * If !rebind, and scratch enabled VMs, there is a chance the scratch | |
| 1676 | + * PTE is already cached in the TLB so it needs to be invalidated. | |
| 1677 | + * On !LR VMs this is done in the ring ops preceding a batch, but on | |
| 1678 | + * non-faulting LR, in particular on user-space batch buffer chaining, | |
| 1679 | + * it needs to be done here. | |
| 1680 | + */ | |
| 1681 | + if ((!pt_op->rebind && xe_vm_has_scratch(vm) && | |
| 1682 | + xe_vm_in_preempt_fence_mode(vm))) | |
| 1683 | + pt_update_ops->needs_invalidation = true; | |
| 1684 | + else if (pt_op->rebind && !xe_vm_in_lr_mode(vm)) | |
| 1685 | + /* We bump also if batch_invalidate_tlb is true */ | |
| 1686 | + vm->tlb_flush_seqno++; | |
| 1687 | + | |
| 1688 | + vma->tile_staged |= BIT(tile->id); | |
| 1689 | + pt_op->vma = vma; | |
| 1690 | + xe_pt_commit_prepare_bind(vma, pt_op->entries, | |
| 1691 | + pt_op->num_entries, pt_op->rebind); | |
| 1692 | + } else { | |
| 1693 | + xe_pt_cancel_bind(vma, pt_op->entries, pt_op->num_entries); | |
| 1694 | + } | |
| 1695 | + | |
| 1696 | + return err; | |
| 1697 | +} | |
| 1698 | + | |
| 1699 | +static int unbind_op_prepare(struct xe_tile *tile, | |
| 1700 | + struct xe_vm_pgtable_update_ops *pt_update_ops, | |
| 1701 | + struct xe_vma *vma) | |
| 1702 | +{ | |
| 1703 | + u32 current_op = pt_update_ops->current_op; | |
| 1704 | + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[current_op]; | |
| 1705 | + int err; | |
| 1706 | + | |
| 1707 | + if (!((vma->tile_present | vma->tile_staged) & BIT(tile->id))) | |
| 1708 | + return 0; | |
| 1709 | + | |
| 1710 | + xe_bo_assert_held(xe_vma_bo(vma)); | |
| 1711 | + | |
| 1712 | + vm_dbg(&xe_vma_vm(vma)->xe->drm, | |
| 1713 | + "Preparing unbind, with range [%llx...%llx)\n", | |
| 1714 | + xe_vma_start(vma), xe_vma_end(vma) - 1); | |
| 1715 | + | |
| 1716 | + /* | |
| 1717 | + * Wait for invalidation to complete. Can corrupt internal page table | |
| 1718 | + * state if an invalidation is running while preparing an unbind. | |
| 1719 | + */ | |
| 1720 | + if (xe_vma_is_userptr(vma) && xe_vm_in_fault_mode(xe_vma_vm(vma))) | |
| 1721 | + mmu_interval_read_begin(&to_userptr_vma(vma)->userptr.notifier); | |
| 1722 | + | |
| 1723 | + pt_op->vma = vma; | |
| 1724 | + pt_op->bind = false; | |
| 1725 | + pt_op->rebind = false; | |
| 1726 | + | |
| 1727 | + err = vma_reserve_fences(tile_to_xe(tile), vma); | |
| 1728 | + if (err) | |
| 1729 | + return err; | |
| 1730 | + | |
| 1731 | + pt_op->num_entries = xe_pt_stage_unbind(tile, vma, pt_op->entries); | |
| 1732 | + | |
| 1733 | + xe_vm_dbg_print_entries(tile_to_xe(tile), pt_op->entries, | |
| 1734 | + pt_op->num_entries, false); | |
| 1735 | + xe_pt_update_ops_rfence_interval(pt_update_ops, vma); | |
| 1736 | + ++pt_update_ops->current_op; | |
| 1737 | + pt_update_ops->needs_userptr_lock |= xe_vma_is_userptr(vma); | |
| 1738 | + pt_update_ops->needs_invalidation = true; | |
| 1739 | + | |
| 1740 | + xe_pt_commit_prepare_unbind(vma, pt_op->entries, pt_op->num_entries); | |
| 1741 | + | |
| 1742 | + return 0; | |
| 1743 | +} | |
| 1744 | + | |
| 1745 | +static int op_prepare(struct xe_vm *vm, | |
| 1746 | + struct xe_tile *tile, | |
| 1747 | + struct xe_vm_pgtable_update_ops *pt_update_ops, | |
| 1748 | + struct xe_vma_op *op) | |
| 1749 | +{ | |
| 1750 | + int err = 0; | |
| 1751 | + | |
| 1752 | + xe_vm_assert_held(vm); | |
| 1753 | + | |
| 1754 | + switch (op->base.op) { | |
| 1755 | + case DRM_GPUVA_OP_MAP: | |
| 1756 | + if (!op->map.immediate && xe_vm_in_fault_mode(vm)) | |
| 1757 | + break; | |
| 1758 | + | |
| 1759 | + err = bind_op_prepare(vm, tile, pt_update_ops, op->map.vma); | |
| 1760 | + pt_update_ops->wait_vm_kernel = true; | |
| 1761 | + break; | |
| 1762 | + case DRM_GPUVA_OP_REMAP: | |
| 1763 | + err = unbind_op_prepare(tile, pt_update_ops, | |
| 1764 | + gpuva_to_vma(op->base.remap.unmap->va)); | |
| 1765 | + | |
| 1766 | + if (!err && op->remap.prev) { | |
| 1767 | + err = bind_op_prepare(vm, tile, pt_update_ops, | |
| 1768 | + op->remap.prev); | |
| 1769 | + pt_update_ops->wait_vm_bookkeep = true; | |
| 1578 | 1770 | } |
| 1771 | + if (!err && op->remap.next) { | |
| 1772 | + err = bind_op_prepare(vm, tile, pt_update_ops, | |
| 1773 | + op->remap.next); | |
| 1774 | + pt_update_ops->wait_vm_bookkeep = true; | |
| 1775 | + } | |
| 1776 | + break; | |
| 1777 | + case DRM_GPUVA_OP_UNMAP: | |
| 1778 | + err = unbind_op_prepare(tile, pt_update_ops, | |
| 1779 | + gpuva_to_vma(op->base.unmap.va)); | |
| 1780 | + break; | |
| 1781 | + case DRM_GPUVA_OP_PREFETCH: | |
| 1782 | + err = bind_op_prepare(vm, tile, pt_update_ops, | |
| 1783 | + gpuva_to_vma(op->base.prefetch.va)); | |
| 1784 | + pt_update_ops->wait_vm_kernel = true; | |
| 1785 | + break; | |
| 1786 | + default: | |
| 1787 | + drm_warn(&vm->xe->drm, "NOT POSSIBLE"); | |
| 1579 | 1788 | } |
| 1789 | + | |
| 1790 | + return err; | |
| 1791 | +} | |
| 1792 | + | |
| 1793 | +static void | |
| 1794 | +xe_pt_update_ops_init(struct xe_vm_pgtable_update_ops *pt_update_ops) | |
| 1795 | +{ | |
| 1796 | + init_llist_head(&pt_update_ops->deferred); | |
| 1797 | + pt_update_ops->start = ~0x0ull; | |
| 1798 | + pt_update_ops->last = 0x0ull; | |
| 1580 | 1799 | } |
| 1581 | 1800 | |
| 1582 | −static const struct xe_migrate_pt_update_ops unbind_ops = { | |
| 1583 | − .populate = xe_migrate_clear_pgtable_callback, | |
| 1801 | +/** | |
| 1802 | + * xe_pt_update_ops_prepare() - Prepare PT update operations | |
| 1803 | + * @tile: Tile of PT update operations | |
| 1804 | + * @vops: VMA operationa | |
| 1805 | + * | |
| 1806 | + * Prepare PT update operations which includes updating internal PT state, | |
| 1807 | + * allocate memory for page tables, populate page table being pruned in, and | |
| 1808 | + * create PT update operations for leaf insertion / removal. | |
| 1809 | + * | |
| 1810 | + * Return: 0 on success, negative error code on error. | |
| 1811 | + */ | |
| 1812 | +int xe_pt_update_ops_prepare(struct xe_tile *tile, struct xe_vma_ops *vops) | |
| 1813 | +{ | |
| 1814 | + struct xe_vm_pgtable_update_ops *pt_update_ops = | |
| 1815 | + &vops->pt_update_ops[tile->id]; | |
| 1816 | + struct xe_vma_op *op; | |
| 1817 | + int err; | |
| 1818 | + | |
| 1819 | + lockdep_assert_held(&vops->vm->lock); | |
| 1820 | + xe_vm_assert_held(vops->vm); | |
| 1821 | + | |
| 1822 | + xe_pt_update_ops_init(pt_update_ops); | |
| 1823 | + | |
| 1824 | + err = dma_resv_reserve_fences(xe_vm_resv(vops->vm), | |
| 1825 | + tile_to_xe(tile)->info.tile_count); | |
| 1826 | + if (err) | |
| 1827 | + return err; | |
| 1828 | + | |
| 1829 | + list_for_each_entry(op, &vops->list, link) { | |
| 1830 | + err = op_prepare(vops->vm, tile, pt_update_ops, op); | |
| 1831 | + | |
| 1832 | + if (err) | |
| 1833 | + return err; | |
| 1834 | + } | |
| 1835 | + | |
| 1836 | + xe_tile_assert(tile, pt_update_ops->current_op <= | |
| 1837 | + pt_update_ops->num_ops); | |
| 1838 | + | |
| 1839 | +#ifdef TEST_VM_OPS_ERROR | |
| 1840 | + if (vops->inject_error && | |
| 1841 | + vops->vm->xe->vm_inject_error_position == FORCE_OP_ERROR_PREPARE) | |
| 1842 | + return -ENOSPC; | |
| 1843 | +#endif | |
| 1844 | + | |
| 1845 | + return 0; | |
| 1846 | +} | |
| 1847 | + | |
| 1848 | +static void bind_op_commit(struct xe_vm *vm, struct xe_tile *tile, | |
| 1849 | + struct xe_vm_pgtable_update_ops *pt_update_ops, | |
| 1850 | + struct xe_vma *vma, struct dma_fence *fence) | |
| 1851 | +{ | |
| 1852 | + if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) | |
| 1853 | + dma_resv_add_fence(xe_vma_bo(vma)->ttm.base.resv, fence, | |
| 1854 | + pt_update_ops->wait_vm_bookkeep ? | |
| 1855 | + DMA_RESV_USAGE_KERNEL : | |
| 1856 | + DMA_RESV_USAGE_BOOKKEEP); | |
| 1857 | + vma->tile_present |= BIT(tile->id); | |
| 1858 | + vma->tile_staged &= ~BIT(tile->id); | |
| 1859 | + if (xe_vma_is_userptr(vma)) { | |
| 1860 | + lockdep_assert_held_read(&vm->userptr.notifier_lock); | |
| 1861 | + to_userptr_vma(vma)->userptr.initial_bind = true; | |
| 1862 | + } | |
| 1863 | + | |
| 1864 | + /* | |
| 1865 | + * Kick rebind worker if this bind triggers preempt fences and not in | |
| 1866 | + * the rebind worker | |
| 1867 | + */ | |
| 1868 | + if (pt_update_ops->wait_vm_bookkeep && | |
| 1869 | + xe_vm_in_preempt_fence_mode(vm) && | |
| 1870 | + !current->mm) | |
| 1871 | + xe_vm_queue_rebind_worker(vm); | |
| 1872 | +} | |
| 1873 | + | |
| 1874 | +static void unbind_op_commit(struct xe_vm *vm, struct xe_tile *tile, | |
| 1875 | + struct xe_vm_pgtable_update_ops *pt_update_ops, | |
| 1876 | + struct xe_vma *vma, struct dma_fence *fence) | |
| 1877 | +{ | |
| 1878 | + if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) | |
| 1879 | + dma_resv_add_fence(xe_vma_bo(vma)->ttm.base.resv, fence, | |
| 1880 | + pt_update_ops->wait_vm_bookkeep ? | |
| 1881 | + DMA_RESV_USAGE_KERNEL : | |
| 1882 | + DMA_RESV_USAGE_BOOKKEEP); | |
| 1883 | + vma->tile_present &= ~BIT(tile->id); | |
| 1884 | + if (!vma->tile_present) { | |
| 1885 | + list_del_init(&vma->combined_links.rebind); | |
| 1886 | + if (xe_vma_is_userptr(vma)) { | |
| 1887 | + lockdep_assert_held_read(&vm->userptr.notifier_lock); | |
| 1888 | + | |
| 1889 | + spin_lock(&vm->userptr.invalidated_lock); | |
| 1890 | + list_del_init(&to_userptr_vma(vma)->userptr.invalidate_link); | |
| 1891 | + spin_unlock(&vm->userptr.invalidated_lock); | |
| 1892 | + } | |
| 1893 | + } | |
| 1894 | +} | |
| 1895 | + | |
| 1896 | +static void op_commit(struct xe_vm *vm, | |
| 1897 | + struct xe_tile *tile, | |
| 1898 | + struct xe_vm_pgtable_update_ops *pt_update_ops, | |
| 1899 | + struct xe_vma_op *op, struct dma_fence *fence) | |
| 1900 | +{ | |
| 1901 | + xe_vm_assert_held(vm); | |
| 1902 | + | |
| 1903 | + switch (op->base.op) { | |
| 1904 | + case DRM_GPUVA_OP_MAP: | |
| 1905 | + if (!op->map.immediate && xe_vm_in_fault_mode(vm)) | |
| 1906 | + break; | |
| 1907 | + | |
| 1908 | + bind_op_commit(vm, tile, pt_update_ops, op->map.vma, fence); | |
| 1909 | + break; | |
| 1910 | + case DRM_GPUVA_OP_REMAP: | |
| 1911 | + unbind_op_commit(vm, tile, pt_update_ops, | |
| 1912 | + gpuva_to_vma(op->base.remap.unmap->va), fence); | |
| 1913 | + | |
| 1914 | + if (op->remap.prev) | |
| 1915 | + bind_op_commit(vm, tile, pt_update_ops, op->remap.prev, | |
| 1916 | + fence); | |
| 1917 | + if (op->remap.next) | |
| 1918 | + bind_op_commit(vm, tile, pt_update_ops, op->remap.next, | |
| 1919 | + fence); | |
| 1920 | + break; | |
| 1921 | + case DRM_GPUVA_OP_UNMAP: | |
| 1922 | + unbind_op_commit(vm, tile, pt_update_ops, | |
| 1923 | + gpuva_to_vma(op->base.unmap.va), fence); | |
| 1924 | + break; | |
| 1925 | + case DRM_GPUVA_OP_PREFETCH: | |
| 1926 | + bind_op_commit(vm, tile, pt_update_ops, | |
| 1927 | + gpuva_to_vma(op->base.prefetch.va), fence); | |
| 1928 | + break; | |
| 1929 | + default: | |
| 1930 | + drm_warn(&vm->xe->drm, "NOT POSSIBLE"); | |
| 1931 | + } | |
| 1932 | +} | |
| 1933 | + | |
| 1934 | +static const struct xe_migrate_pt_update_ops migrate_ops = { | |
| 1935 | + .populate = xe_vm_populate_pgtable, | |
| 1936 | + .clear = xe_migrate_clear_pgtable_callback, | |
| 1584 | 1937 | .pre_commit = xe_pt_pre_commit, |
| 1585 | 1938 | }; |
| 1586 | 1939 | |
| 1587 | −static const struct xe_migrate_pt_update_ops userptr_unbind_ops = { | |
| 1588 | − .populate = xe_migrate_clear_pgtable_callback, | |
| 1940 | +static const struct xe_migrate_pt_update_ops userptr_migrate_ops = { | |
| 1941 | + .populate = xe_vm_populate_pgtable, | |
| 1942 | + .clear = xe_migrate_clear_pgtable_callback, | |
| 1589 | 1943 | .pre_commit = xe_pt_userptr_pre_commit, |
| 1590 | 1944 | }; |
| 1591 | 1945 | |
| 1592 | 1946 | /** |
| 1593 | − * __xe_pt_unbind_vma() - Disconnect and free a page-table tree for the vma | |
| 1594 | − * address range. | |
| 1595 | − * @tile: The tile to unbind for. | |
| 1596 | − * @vma: The vma to unbind. | |
| 1597 | − * @q: The exec_queue with which to do pipelined page-table updates. | |
| 1598 | − * @syncs: Entries to sync on before disconnecting the tree to be destroyed. | |
| 1599 | − * @num_syncs: Number of @sync entries. | |
| 1947 | + * xe_pt_update_ops_run() - Run PT update operations | |
| 1948 | + * @tile: Tile of PT update operations | |
| 1949 | + * @vops: VMA operationa | |
| 1600 | 1950 | * |
| 1601 | − * This function builds a the xe_vm_pgtable_update entries abstracting the | |
| 1602 | − * operations needed to detach the page-table tree to be destroyed from the | |
| 1603 | − * man vm tree. | |
| 1604 | − * It then takes the relevant locks and submits the operations for | |
| 1605 | − * pipelined detachment of the gpu page-table from the vm main tree, | |
| 1606 | − * (which can be done either by the cpu and the GPU), Finally it frees the | |
| 1607 | − * detached page-table tree. | |
| 1951 | + * Run PT update operations which includes committing internal PT state changes, | |
| 1952 | + * creating job for PT update operations for leaf insertion / removal, and | |
| 1953 | + * installing job fence in various places. | |
| 1608 | 1954 | * |
| 1609 | − * Return: A valid dma-fence representing the pipelined detachment operation | |
| 1610 | − * on success, an error pointer on error. | |
| 1955 | + * Return: fence on success, negative ERR_PTR on error. | |
| 1611 | 1956 | */ |
| 1612 | 1957 | struct dma_fence * |
| 1613 | −__xe_pt_unbind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue *q, | |
| 1614 | − struct xe_sync_entry *syncs, u32 num_syncs) | |
| 1958 | +xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops) | |
| 1615 | 1959 | { |
| 1616 | − struct xe_vm_pgtable_update entries[XE_VM_MAX_LEVEL * 2 + 1]; | |
| 1617 | − struct xe_pt_migrate_pt_update unbind_pt_update = { | |
| 1618 | − .base = { | |
| 1619 | − .ops = xe_vma_is_userptr(vma) ? &userptr_unbind_ops : | |
| 1620 | − &unbind_ops, | |
| 1621 | − .vma = vma, | |
| 1622 | − .tile_id = tile->id, | |
| 1623 | − }, | |
| 1624 | − }; | |
| 1625 | − struct xe_vm *vm = xe_vma_vm(vma); | |
| 1626 | − u32 num_entries; | |
| 1627 | − struct dma_fence *fence = NULL; | |
| 1628 | − struct invalidation_fence *ifence; | |
| 1960 | + struct xe_vm *vm = vops->vm; | |
| 1961 | + struct xe_vm_pgtable_update_ops *pt_update_ops = | |
| 1962 | + &vops->pt_update_ops[tile->id]; | |
| 1963 | + struct dma_fence *fence; | |
| 1964 | + struct invalidation_fence *ifence = NULL; | |
| 1629 | 1965 | struct xe_range_fence *rfence; |
| 1630 | − int err; | |
| 1631 | − | |
| 1632 | − LLIST_HEAD(deferred); | |
| 1966 | + struct xe_vma_op *op; | |
| 1967 | + int err = 0, i; | |
| 1968 | + struct xe_migrate_pt_update update = { | |
| 1969 | + .ops = pt_update_ops->needs_userptr_lock ? | |
| 1970 | + &userptr_migrate_ops : | |
| 1971 | + &migrate_ops, | |
| 1972 | + .vops = vops, | |
| 1973 | + .tile_id = tile->id, | |
| 1974 | + }; | |
| 1633 | 1975 | |
| 1634 | − xe_bo_assert_held(xe_vma_bo(vma)); | |
| 1976 | + lockdep_assert_held(&vm->lock); | |
| 1635 | 1977 | xe_vm_assert_held(vm); |
| 1636 | 1978 | |
| 1637 | − vm_dbg(&xe_vma_vm(vma)->xe->drm, | |
| 1638 | − "Preparing unbind, with range [%llx...%llx) engine %p.\n", | |
| 1639 | − xe_vma_start(vma), xe_vma_end(vma), q); | |
| 1640 | − | |
| 1641 | − num_entries = xe_pt_stage_unbind(tile, vma, entries); | |
| 1642 | − xe_tile_assert(tile, num_entries <= ARRAY_SIZE(entries)); | |
| 1979 | + if (!pt_update_ops->current_op) { | |
| 1980 | + xe_tile_assert(tile, xe_vm_in_fault_mode(vm)); | |
| 1643 | 1981 | |
| 1644 | − xe_vm_dbg_print_entries(tile_to_xe(tile), entries, num_entries); | |
| 1645 | − xe_pt_calc_rfence_interval(vma, &unbind_pt_update, entries, | |
| 1646 | − num_entries); | |
| 1982 | + return dma_fence_get_stub(); | |
| 1983 | + } | |
| 1647 | 1984 | |
| 1648 | − err = dma_resv_reserve_fences(xe_vm_resv(vm), 1); | |
| 1649 | − if (!err && !xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) | |
| 1650 | − err = dma_resv_reserve_fences(xe_vma_bo(vma)->ttm.base.resv, 1); | |
| 1651 | − if (err) | |
| 1652 | − return ERR_PTR(err); | |
| 1985 | +#ifdef TEST_VM_OPS_ERROR | |
| 1986 | + if (vops->inject_error && | |
| 1987 | + vm->xe->vm_inject_error_position == FORCE_OP_ERROR_RUN) | |
| 1988 | + return ERR_PTR(-ENOSPC); | |
| 1989 | +#endif | |
| 1653 | 1990 | |
| 1654 | − ifence = kzalloc(sizeof(*ifence), GFP_KERNEL); | |
| 1655 | − if (!ifence) | |
| 1656 | − return ERR_PTR(-ENOMEM); | |
| 1991 | + if (pt_update_ops->needs_invalidation) { | |
| 1992 | + ifence = kzalloc(sizeof(*ifence), GFP_KERNEL); | |
| 1993 | + if (!ifence) { | |
| 1994 | + err = -ENOMEM; | |
| 1995 | + goto kill_vm_tile1; | |
| 1996 | + } | |
| 1997 | + } | |
| 1657 | 1998 | |
| 1658 | 1999 | rfence = kzalloc(sizeof(*rfence), GFP_KERNEL); |
| 1659 | 2000 | if (!rfence) { |
| 1660 | − kfree(ifence); | |
| 1661 | − return ERR_PTR(-ENOMEM); | |
| 2001 | + err = -ENOMEM; | |
| 2002 | + goto free_ifence; | |
| 1662 | 2003 | } |
| 1663 | 2004 | |
| 1664 | − /* | |
| 1665 | − * Even if we were already evicted and unbind to destroy, we need to | |
| 1666 | − * clear again here. The eviction may have updated pagetables at a | |
| 1667 | − * lower level, because it needs to be more conservative. | |
| 1668 | − */ | |
| 1669 | − fence = xe_migrate_update_pgtables(tile->migrate, | |
| 1670 | − vm, NULL, q ? q : | |
| 1671 | − vm->q[tile->id], | |
| 1672 | − entries, num_entries, | |
| 1673 | − syncs, num_syncs, | |
| 1674 | − &unbind_pt_update.base); | |
| 1675 | − if (!IS_ERR(fence)) { | |
| 1676 | − int err; | |
| 1677 | − | |
| 1678 | − err = xe_range_fence_insert(&vm->rftree[tile->id], rfence, | |
| 1679 | − &xe_range_fence_kfree_ops, | |
| 1680 | − unbind_pt_update.base.start, | |
| 1681 | − unbind_pt_update.base.last, fence); | |
| 1682 | − if (err) | |
| 1683 | − dma_fence_wait(fence, false); | |
| 2005 | + fence = xe_migrate_update_pgtables(tile->migrate, &update); | |
| 2006 | + if (IS_ERR(fence)) { | |
| 2007 | + err = PTR_ERR(fence); | |
| 2008 | + goto free_rfence; | |
| 2009 | + } | |
| 1684 | 2010 | |
| 1685 | − /* TLB invalidation must be done before signaling unbind */ | |
| 1686 | − err = invalidation_fence_init(tile->primary_gt, ifence, fence, | |
| 1687 | − xe_vma_start(vma), | |
| 1688 | − xe_vma_end(vma), | |
| 1689 | − xe_vma_vm(vma)->usm.asid); | |
| 1690 | − if (err) { | |
| 1691 | − dma_fence_put(fence); | |
| 1692 | − kfree(ifence); | |
| 1693 | − return ERR_PTR(err); | |
| 1694 | − } | |
| 1695 | − fence = &ifence->base.base; | |
| 2011 | + /* Point of no return - VM killed if failure after this */ | |
| 2012 | + for (i = 0; i < pt_update_ops->current_op; ++i) { | |
| 2013 | + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[i]; | |
| 1696 | 2014 | |
| 1697 | − /* add shared fence now for pagetable delayed destroy */ | |
| 1698 | − dma_resv_add_fence(xe_vm_resv(vm), fence, | |
| 1699 | − DMA_RESV_USAGE_BOOKKEEP); | |
| 2015 | + xe_pt_commit(pt_op->vma, pt_op->entries, | |
| 2016 | + pt_op->num_entries, &pt_update_ops->deferred); | |
| 2017 | + pt_op->vma = NULL; /* skip in xe_pt_update_ops_abort */ | |
| 2018 | + } | |
| 1700 | 2019 | |
| 1701 | − /* This fence will be installed by caller when doing eviction */ | |
| 1702 | − if (!xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm) | |
| 1703 | − dma_resv_add_fence(xe_vma_bo(vma)->ttm.base.resv, fence, | |
| 1704 | − DMA_RESV_USAGE_BOOKKEEP); | |
| 1705 | − xe_pt_commit_unbind(vma, entries, num_entries, | |
| 1706 | − unbind_pt_update.locked ? &deferred : NULL); | |
| 1707 | − vma->tile_present &= ~BIT(tile->id); | |
| 1708 | − } else { | |
| 1709 | − kfree(rfence); | |
| 1710 | − kfree(ifence); | |
| 2020 | + if (xe_range_fence_insert(&vm->rftree[tile->id], rfence, | |
| 2021 | + &xe_range_fence_kfree_ops, | |
| 2022 | + pt_update_ops->start, | |
| 2023 | + pt_update_ops->last, fence)) | |
| 2024 | + dma_fence_wait(fence, false); | |
| 2025 | + | |
| 2026 | + /* tlb invalidation must be done before signaling rebind */ | |
| 2027 | + if (ifence) { | |
| 2028 | + invalidation_fence_init(tile->primary_gt, ifence, fence, | |
| 2029 | + pt_update_ops->start, | |
| 2030 | + pt_update_ops->last, vm->usm.asid); | |
| 2031 | + fence = &ifence->base.base; | |
| 1711 | 2032 | } |
| 1712 | 2033 | |
| 1713 | − if (!vma->tile_present) | |
| 1714 | − list_del_init(&vma->combined_links.rebind); | |
| 2034 | + dma_resv_add_fence(xe_vm_resv(vm), fence, | |
| 2035 | + pt_update_ops->wait_vm_bookkeep ? | |
| 2036 | + DMA_RESV_USAGE_KERNEL : | |
| 2037 | + DMA_RESV_USAGE_BOOKKEEP); | |
| 1715 | 2038 | |
| 1716 | − if (unbind_pt_update.locked) { | |
| 1717 | − xe_tile_assert(tile, xe_vma_is_userptr(vma)); | |
| 2039 | + list_for_each_entry(op, &vops->list, link) | |
| 2040 | + op_commit(vops->vm, tile, pt_update_ops, op, fence); | |
| 1718 | 2041 | |
| 1719 | − if (!vma->tile_present) { | |
| 1720 | − spin_lock(&vm->userptr.invalidated_lock); | |
| 1721 | − list_del_init(&to_userptr_vma(vma)->userptr.invalidate_link); | |
| 1722 | − spin_unlock(&vm->userptr.invalidated_lock); | |
| 1723 | − } | |
| 2042 | + if (pt_update_ops->needs_userptr_lock) | |
| 1724 | 2043 | up_read(&vm->userptr.notifier_lock); |
| 1725 | − xe_bo_put_commit(&deferred); | |
| 1726 | − } | |
| 1727 | 2044 | |
| 1728 | 2045 | return fence; |
| 2046 | + | |
| 2047 | +free_rfence: | |
| 2048 | + kfree(rfence); | |
| 2049 | +free_ifence: | |
| 2050 | + kfree(ifence); | |
| 2051 | +kill_vm_tile1: | |
| 2052 | + if (err != -EAGAIN && tile->id) | |
| 2053 | + xe_vm_kill(vops->vm, false); | |
| 2054 | + | |
| 2055 | + return ERR_PTR(err); | |
| 2056 | +} | |
| 2057 | + | |
| 2058 | +/** | |
| 2059 | + * xe_pt_update_ops_fini() - Finish PT update operations | |
| 2060 | + * @tile: Tile of PT update operations | |
| 2061 | + * @vops: VMA operations | |
| 2062 | + * | |
| 2063 | + * Finish PT update operations by committing to destroy page table memory | |
| 2064 | + */ | |
| 2065 | +void xe_pt_update_ops_fini(struct xe_tile *tile, struct xe_vma_ops *vops) | |
| 2066 | +{ | |
| 2067 | + struct xe_vm_pgtable_update_ops *pt_update_ops = | |
| 2068 | + &vops->pt_update_ops[tile->id]; | |
| 2069 | + int i; | |
| 2070 | + | |
| 2071 | + lockdep_assert_held(&vops->vm->lock); | |
| 2072 | + xe_vm_assert_held(vops->vm); | |
| 2073 | + | |
| 2074 | + for (i = 0; i < pt_update_ops->current_op; ++i) { | |
| 2075 | + struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[i]; | |
| 2076 | + | |
| 2077 | + xe_pt_free_bind(pt_op->entries, pt_op->num_entries); | |
| 2078 | + } | |
| 2079 | + xe_bo_put_commit(&vops->pt_update_ops[tile->id].deferred); | |
| 2080 | +} | |
| 2081 | + | |
| 2082 | +/** | |
| 2083 | + * xe_pt_update_ops_abort() - Abort PT update operations | |
| 2084 | + * @tile: Tile of PT update operations | |
| 2085 | + * @vops: VMA operationa | |
| 2086 | + * | |
| 2087 | + * Abort PT update operations by unwinding internal PT state | |
| 2088 | + */ | |
| 2089 | +void xe_pt_update_ops_abort(struct xe_tile *tile, struct xe_vma_ops *vops) | |
| 2090 | +{ | |
| 2091 | + struct xe_vm_pgtable_update_ops *pt_update_ops = | |
| 2092 | + &vops->pt_update_ops[tile->id]; | |
| 2093 | + int i; | |
| 2094 | + | |
| 2095 | + lockdep_assert_held(&vops->vm->lock); | |
| 2096 | + xe_vm_assert_held(vops->vm); | |
| 2097 | + | |
| 2098 | + for (i = pt_update_ops->num_ops - 1; i >= 0; --i) { | |
| 2099 | + struct xe_vm_pgtable_update_op *pt_op = | |
| 2100 | + &pt_update_ops->ops[i]; | |
| 2101 | + | |
| 2102 | + if (!pt_op->vma || i >= pt_update_ops->current_op) | |
| 2103 | + continue; | |
| 2104 | + | |
| 2105 | + if (pt_op->bind) | |
| 2106 | + xe_pt_abort_bind(pt_op->vma, pt_op->entries, | |
| 2107 | + pt_op->num_entries, | |
| 2108 | + pt_op->rebind); | |
| 2109 | + else | |
| 2110 | + xe_pt_abort_unbind(pt_op->vma, pt_op->entries, | |
| 2111 | + pt_op->num_entries); | |
| 2112 | + } | |
| 2113 | + | |
| 2114 | + xe_bo_put_commit(&vops->pt_update_ops[tile->id].deferred); | |
| 1729 | 2115 | } |
| @@ -17,6 +17,7 @@ struct xe_sync_entry; · 16 unmodified lines | ||
| 17 | 17 | struct xe_tile; |
| 18 | 18 | struct xe_vm; |
| 19 | 19 | struct xe_vma; |
| 20 | +struct xe_vma_ops; | |
| 20 | 21 | |
| 21 | 22 | /* Largest huge pte is currently 1GiB. May become device dependent. */ |
| 22 | 23 | #define MAX_HUGEPTE_LEVEL 2 |
| @@ -34,14 +35,11 @@ void xe_pt_populate_empty(struct xe_tile *tile, struct xe_vm *vm, · 11 unmodified lines | ||
| 34 | 35 | |
| 35 | 36 | void xe_pt_destroy(struct xe_pt *pt, u32 flags, struct llist_head *deferred); |
| 36 | 37 | |
| 37 | −struct dma_fence * | |
| 38 | −__xe_pt_bind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue *q, | |
| 39 | − struct xe_sync_entry *syncs, u32 num_syncs, | |
| 40 | − bool rebind); | |
| 41 | − | |
| 42 | −struct dma_fence * | |
| 43 | −__xe_pt_unbind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue *q, | |
| 44 | − struct xe_sync_entry *syncs, u32 num_syncs); | |
| 38 | +int xe_pt_update_ops_prepare(struct xe_tile *tile, struct xe_vma_ops *vops); | |
| 39 | +struct dma_fence *xe_pt_update_ops_run(struct xe_tile *tile, | |
| 40 | + struct xe_vma_ops *vops); | |
| 41 | +void xe_pt_update_ops_fini(struct xe_tile *tile, struct xe_vma_ops *vops); | |
| 42 | +void xe_pt_update_ops_abort(struct xe_tile *tile, struct xe_vma_ops *vops); | |
| 45 | 43 | |
| 46 | 44 | bool xe_pt_zap_ptes(struct xe_tile *tile, struct xe_vma *vma); |
| 47 | 45 | |
| @@ -74,4 +74,52 @@ struct xe_vm_pgtable_update { · 73 unmodified lines | ||
| 74 | 74 | u32 flags; |
| 75 | 75 | }; |
| 76 | 76 | |
| 77 | +/** struct xe_vm_pgtable_update_op - Page table update operation */ | |
| 78 | +struct xe_vm_pgtable_update_op { | |
| 79 | + /** @entries: entries to update for this operation */ | |
| 80 | + struct xe_vm_pgtable_update entries[XE_VM_MAX_LEVEL * 2 + 1]; | |
| 81 | + /** @vma: VMA for operation, operation not valid if NULL */ | |
| 82 | + struct xe_vma *vma; | |
| 83 | + /** @num_entries: number of entries for this update operation */ | |
| 84 | + u32 num_entries; | |
| 85 | + /** @bind: is a bind */ | |
| 86 | + bool bind; | |
| 87 | + /** @rebind: is a rebind */ | |
| 88 | + bool rebind; | |
| 89 | +}; | |
| 90 | + | |
| 91 | +/** struct xe_vm_pgtable_update_ops: page table update operations */ | |
| 92 | +struct xe_vm_pgtable_update_ops { | |
| 93 | + /** @ops: operations */ | |
| 94 | + struct xe_vm_pgtable_update_op *ops; | |
| 95 | + /** @deferred: deferred list to destroy PT entries */ | |
| 96 | + struct llist_head deferred; | |
| 97 | + /** @q: exec queue for PT operations */ | |
| 98 | + struct xe_exec_queue *q; | |
| 99 | + /** @start: start address of ops */ | |
| 100 | + u64 start; | |
| 101 | + /** @last: last address of ops */ | |
| 102 | + u64 last; | |
| 103 | + /** @num_ops: number of operations */ | |
| 104 | + u32 num_ops; | |
| 105 | + /** @current_op: current operations */ | |
| 106 | + u32 current_op; | |
| 107 | + /** @needs_userptr_lock: Needs userptr lock */ | |
| 108 | + bool needs_userptr_lock; | |
| 109 | + /** @needs_invalidation: Needs invalidation */ | |
| 110 | + bool needs_invalidation; | |
| 111 | + /** | |
| 112 | + * @wait_vm_bookkeep: PT operations need to wait until VM is idle | |
| 113 | + * (bookkeep dma-resv slots are idle) and stage all future VM activity | |
| 114 | + * behind these operations (install PT operations into VM kernel | |
| 115 | + * dma-resv slot). | |
| 116 | + */ | |
| 117 | + bool wait_vm_bookkeep; | |
| 118 | + /** | |
| 119 | + * @wait_vm_kernel: PT operations need to wait until VM kernel dma-resv | |
| 120 | + * slots are idle. | |
| 121 | + */ | |
| 122 | + bool wait_vm_kernel; | |
| 123 | +}; | |
| 124 | + | |
| 77 | 125 | #endif |
| @@ -518,7 +518,9 @@ static int query_gt_topology(struct xe_device *xe, · 517 unmodified lines | ||
| 518 | 518 | if (err) |
| 519 | 519 | return err; |
| 520 | 520 | |
| 521 | − topo.type = DRM_XE_TOPO_EU_PER_DSS; | |
| 521 | + topo.type = gt->fuse_topo.eu_type == XE_GT_EU_TYPE_SIMD16 ? | |
| 522 | + DRM_XE_TOPO_SIMD16_EU_PER_DSS : | |
| 523 | + DRM_XE_TOPO_EU_PER_DSS; | |
| 522 | 524 | err = copy_mask(&query_ptr, &topo, |
| 523 | 525 | gt->fuse_topo.eu_mask_per_dss, |
| 524 | 526 | sizeof(gt->fuse_topo.eu_mask_per_dss)); |
| @@ -217,21 +217,19 @@ void xe_rtp_process_ctx_enable_active_tracking(struct xe_rtp_process_ctx *ctx, · 216 unmodified lines | ||
| 217 | 217 | ctx->active_entries = active_entries; |
| 218 | 218 | ctx->n_entries = n_entries; |
| 219 | 219 | } |
| 220 | +EXPORT_SYMBOL_IF_KUNIT(xe_rtp_process_ctx_enable_active_tracking); | |
| 220 | 221 | |
| 221 | 222 | static void rtp_mark_active(struct xe_device *xe, |
| 222 | 223 | struct xe_rtp_process_ctx *ctx, |
| 223 | − unsigned int first, unsigned int last) | |
| 224 | + unsigned int idx) | |
| 224 | 225 | { |
| 225 | 226 | if (!ctx->active_entries) |
| 226 | 227 | return; |
| 227 | 228 | |
| 228 | − if (drm_WARN_ON(&xe->drm, last > ctx->n_entries)) | |
| 229 | + if (drm_WARN_ON(&xe->drm, idx >= ctx->n_entries)) | |
| 229 | 230 | return; |
| 230 | 231 | |
| 231 | − if (first == last) | |
| 232 | − bitmap_set(ctx->active_entries, first, 1); | |
| 233 | − else | |
| 234 | − bitmap_set(ctx->active_entries, first, last - first + 2); | |
| 232 | + bitmap_set(ctx->active_entries, idx, 1); | |
| 235 | 233 | } |
| 236 | 234 | |
| 237 | 235 | /** |
| @@ -276,8 +274,7 @@ void xe_rtp_process_to_sr(struct xe_rtp_process_ctx *ctx, · 38 unmodified lines | ||
| 276 | 274 | } |
| 277 | 275 | |
| 278 | 276 | if (match) |
| 279 | − rtp_mark_active(xe, ctx, entry - entries, | |
| 280 | − entry - entries); | |
| 277 | + rtp_mark_active(xe, ctx, entry - entries); | |
| 281 | 278 | } |
| 282 | 279 | } |
| 283 | 280 | EXPORT_SYMBOL_IF_KUNIT(xe_rtp_process_to_sr); |
| @@ -288,44 +285,29 @@ EXPORT_SYMBOL_IF_KUNIT(xe_rtp_process_to_sr); · 4 unmodified lines | ||
| 288 | 285 | * @entries: Table with RTP definitions |
| 289 | 286 | * |
| 290 | 287 | * Walk the table pointed by @entries (with an empty sentinel), executing the |
| 291 | − * rules. A few differences from xe_rtp_process_to_sr(): | |
| 292 | − * | |
| 293 | − * 1. There is no action associated with each entry since this uses | |
| 294 | − * struct xe_rtp_entry. Its main use is for marking active workarounds via | |
| 295 | − * xe_rtp_process_ctx_enable_active_tracking(). | |
| 296 | − * 2. There is support for OR operations by having entries with no name. | |
| 288 | + * rules. One difference from xe_rtp_process_to_sr(): there is no action | |
| 289 | + * associated with each entry since this uses struct xe_rtp_entry. Its main use | |
| 290 | + * is for marking active workarounds via | |
| 291 | + * xe_rtp_process_ctx_enable_active_tracking(). | |
| 297 | 292 | */ |
| 298 | 293 | void xe_rtp_process(struct xe_rtp_process_ctx *ctx, |
| 299 | 294 | const struct xe_rtp_entry *entries) |
| 300 | 295 | { |
| 301 | − const struct xe_rtp_entry *entry, *first_entry; | |
| 296 | + const struct xe_rtp_entry *entry; | |
| 302 | 297 | struct xe_hw_engine *hwe; |
| 303 | 298 | struct xe_gt *gt; |
| 304 | 299 | struct xe_device *xe; |
| 305 | 300 | |
| 306 | 301 | rtp_get_context(ctx, &hwe, >, &xe); |
| 307 | 302 | |
| 308 | − first_entry = entries; | |
| 309 | − if (drm_WARN_ON(&xe->drm, !first_entry->name)) | |
| 310 | − return; | |
| 311 | − | |
| 312 | 303 | for (entry = entries; entry && entry->rules; entry++) { |
| 313 | − if (entry->name) | |
| 314 | − first_entry = entry; | |
| 315 | − | |
| 316 | 304 | if (!rule_matches(xe, gt, hwe, entry->rules, entry->n_rules)) |
| 317 | 305 | continue; |
| 318 | 306 | |
| 319 | − /* Fast-forward entry, eliminating the OR'ed entries */ | |
| 320 | − for (entry++; entry && entry->rules; entry++) | |
| 321 | − if (entry->name) | |
| 322 | − break; | |
| 323 | − entry--; | |
| 324 | − | |
| 325 | − rtp_mark_active(xe, ctx, first_entry - entries, | |
| 326 | − entry - entries); | |
| 307 | + rtp_mark_active(xe, ctx, entry - entries); | |
| 327 | 308 | } |
| 328 | 309 | } |
| 310 | +EXPORT_SYMBOL_IF_KUNIT(xe_rtp_process); | |
| 329 | 311 | |
| 330 | 312 | bool xe_rtp_match_even_instance(const struct xe_gt *gt, |
| 331 | 313 | const struct xe_hw_engine *hwe) |
| @@ -374,7 +374,7 @@ struct xe_reg_sr; · 373 unmodified lines | ||
| 374 | 374 | * XE_RTP_RULES - Helper to set multiple rules to a struct xe_rtp_entry_sr entry |
| 375 | 375 | * @...: Rules |
| 376 | 376 | * |
| 377 | − * At least one rule is needed and up to 6 are supported. Multiple rules are | |
| 377 | + * At least one rule is needed and up to 12 are supported. Multiple rules are | |
| 378 | 378 | * AND'ed together, i.e. all the rules must evaluate to true for the entry to |
| 379 | 379 | * be processed. See XE_RTP_MATCH_* for the possible match rules. Example: |
| 380 | 380 | * |
| @@ -399,7 +399,7 @@ struct xe_reg_sr; · 18 unmodified lines | ||
| 399 | 399 | * XE_RTP_ACTIONS - Helper to set multiple actions to a struct xe_rtp_entry_sr |
| 400 | 400 | * @...: Actions to be taken |
| 401 | 401 | * |
| 402 | − * At least one action is needed and up to 6 are supported. See XE_RTP_ACTION_* | |
| 402 | + * At least one action is needed and up to 12 are supported. See XE_RTP_ACTION_* | |
| 403 | 403 | * for the possible actions. Example: |
| 404 | 404 | * |
| 405 | 405 | * .. code-block:: c |
| @@ -60,6 +60,12 @@ · 59 unmodified lines | ||
| 60 | 60 | #define XE_RTP_PASTE_4(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_3(prefix_, sep_, _XE_TUPLE_TAIL args_) |
| 61 | 61 | #define XE_RTP_PASTE_5(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_4(prefix_, sep_, _XE_TUPLE_TAIL args_) |
| 62 | 62 | #define XE_RTP_PASTE_6(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_5(prefix_, sep_, _XE_TUPLE_TAIL args_) |
| 63 | +#define XE_RTP_PASTE_7(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_6(prefix_, sep_, _XE_TUPLE_TAIL args_) | |
| 64 | +#define XE_RTP_PASTE_8(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_7(prefix_, sep_, _XE_TUPLE_TAIL args_) | |
| 65 | +#define XE_RTP_PASTE_9(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_8(prefix_, sep_, _XE_TUPLE_TAIL args_) | |
| 66 | +#define XE_RTP_PASTE_10(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_9(prefix_, sep_, _XE_TUPLE_TAIL args_) | |
| 67 | +#define XE_RTP_PASTE_11(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_10(prefix_, sep_, _XE_TUPLE_TAIL args_) | |
| 68 | +#define XE_RTP_PASTE_12(prefix_, sep_, args_) _XE_RTP_CONCAT(prefix_, FIRST_ARG args_) __XE_RTP_PASTE_SEP_ ## sep_ XE_RTP_PASTE_11(prefix_, sep_, _XE_TUPLE_TAIL args_) | |
| 63 | 69 | |
| 64 | 70 | /* |
| 65 | 71 | * XE_RTP_DROP_CAST - Drop cast to convert a compound statement to a initializer |
| @@ -84,6 +84,13 @@ struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 · 83 unmodified lines | ||
| 84 | 84 | struct drm_suballoc *xe_sa_bo_new(struct xe_sa_manager *sa_manager, |
| 85 | 85 | unsigned int size) |
| 86 | 86 | { |
| 87 | + /* | |
| 88 | + * BB to large, return -ENOBUFS indicating user should split | |
| 89 | + * array of binds into smaller chunks. | |
| 90 | + */ | |
| 91 | + if (size > sa_manager->base.size) | |
| 92 | + return ERR_PTR(-ENOBUFS); | |
| 93 | + | |
| 87 | 94 | return drm_suballoc_new(&sa_manager->base, size, GFP_KERNEL, true, 0); |
| 88 | 95 | } |
| 89 | 96 | |
| @@ -5,7 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | |
| 6 | 6 | #include <drm/drm_managed.h> |
| 7 | 7 | |
| 8 | −#include "regs/xe_sriov_regs.h" | |
| 8 | +#include "regs/xe_regs.h" | |
| 9 | 9 | |
| 10 | 10 | #include "xe_assert.h" |
| 11 | 11 | #include "xe_device.h" |
| @@ -53,14 +53,18 @@ static struct xe_user_fence *user_fence_create(struct xe_device *xe, u64 addr, · 52 unmodified lines | ||
| 53 | 53 | u64 value) |
| 54 | 54 | { |
| 55 | 55 | struct xe_user_fence *ufence; |
| 56 | + u64 __user *ptr = u64_to_user_ptr(addr); | |
| 57 | + | |
| 58 | + if (!access_ok(ptr, sizeof(ptr))) | |
| 59 | + return ERR_PTR(-EFAULT); | |
| 56 | 60 | |
| 57 | 61 | ufence = kmalloc(sizeof(*ufence), GFP_KERNEL); |
| 58 | 62 | if (!ufence) |
| 59 | − return NULL; | |
| 63 | + return ERR_PTR(-ENOMEM); | |
| 60 | 64 | |
| 61 | 65 | ufence->xe = xe; |
| 62 | 66 | kref_init(&ufence->refcount); |
| 63 | − ufence->addr = u64_to_user_ptr(addr); | |
| 67 | + ufence->addr = ptr; | |
| 64 | 68 | ufence->value = value; |
| 65 | 69 | ufence->mm = current->mm; |
| 66 | 70 | mmgrab(ufence->mm); |
| @@ -183,8 +187,8 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef, · 116 unmodified lines | ||
| 183 | 187 | } else { |
| 184 | 188 | sync->ufence = user_fence_create(xe, sync_in.addr, |
| 185 | 189 | sync_in.timeline_value); |
| 186 | − if (XE_IOCTL_DBG(xe, !sync->ufence)) | |
| 187 | − return -ENOMEM; | |
| 190 | + if (XE_IOCTL_DBG(xe, IS_ERR(sync->ufence))) | |
| 191 | + return PTR_ERR(sync->ufence); | |
| 188 | 192 | } |
| 189 | 193 | |
| 190 | 194 | break; |
| @@ -200,14 +204,6 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef, · 9 unmodified lines | ||
| 200 | 204 | return 0; |
| 201 | 205 | } |
| 202 | 206 | |
| 203 | −int xe_sync_entry_wait(struct xe_sync_entry *sync) | |
| 204 | −{ | |
| 205 | − if (sync->fence) | |
| 206 | − dma_fence_wait(sync->fence, true); | |
| 207 | − | |
| 208 | − return 0; | |
| 209 | −} | |
| 210 | − | |
| 211 | 207 | int xe_sync_entry_add_deps(struct xe_sync_entry *sync, struct xe_sched_job *job) |
| 212 | 208 | { |
| 213 | 209 | int err; |
| @@ -22,7 +22,6 @@ int xe_sync_entry_parse(struct xe_device *xe, struct xe_file *xef, · 21 unmodified lines | ||
| 22 | 22 | struct xe_sync_entry *sync, |
| 23 | 23 | struct drm_xe_sync __user *sync_user, |
| 24 | 24 | unsigned int flags); |
| 25 | −int xe_sync_entry_wait(struct xe_sync_entry *sync); | |
| 26 | 25 | int xe_sync_entry_add_deps(struct xe_sync_entry *sync, |
| 27 | 26 | struct xe_sched_job *job); |
| 28 | 27 | void xe_sync_entry_signal(struct xe_sync_entry *sync, |
| @@ -369,6 +369,58 @@ TRACE_EVENT(xe_reg_rw, · 368 unmodified lines | ||
| 369 | 369 | (u32)(__entry->val >> 32)) |
| 370 | 370 | ); |
| 371 | 371 | |
| 372 | +DECLARE_EVENT_CLASS(xe_pm_runtime, | |
| 373 | + TP_PROTO(struct xe_device *xe, void *caller), | |
| 374 | + TP_ARGS(xe, caller), | |
| 375 | + | |
| 376 | + TP_STRUCT__entry( | |
| 377 | + __string(dev, __dev_name_xe(xe)) | |
| 378 | + __field(void *, caller) | |
| 379 | + ), | |
| 380 | + | |
| 381 | + TP_fast_assign( | |
| 382 | + __assign_str(dev); | |
| 383 | + __entry->caller = caller; | |
| 384 | + ), | |
| 385 | + | |
| 386 | + TP_printk("dev=%s caller_function=%pS", __get_str(dev), __entry->caller) | |
| 387 | +); | |
| 388 | + | |
| 389 | +DEFINE_EVENT(xe_pm_runtime, xe_pm_runtime_get, | |
| 390 | + TP_PROTO(struct xe_device *xe, void *caller), | |
| 391 | + TP_ARGS(xe, caller) | |
| 392 | +); | |
| 393 | + | |
| 394 | +DEFINE_EVENT(xe_pm_runtime, xe_pm_runtime_put, | |
| 395 | + TP_PROTO(struct xe_device *xe, void *caller), | |
| 396 | + TP_ARGS(xe, caller) | |
| 397 | +); | |
| 398 | + | |
| 399 | +DEFINE_EVENT(xe_pm_runtime, xe_pm_resume, | |
| 400 | + TP_PROTO(struct xe_device *xe, void *caller), | |
| 401 | + TP_ARGS(xe, caller) | |
| 402 | +); | |
| 403 | + | |
| 404 | +DEFINE_EVENT(xe_pm_runtime, xe_pm_suspend, | |
| 405 | + TP_PROTO(struct xe_device *xe, void *caller), | |
| 406 | + TP_ARGS(xe, caller) | |
| 407 | +); | |
| 408 | + | |
| 409 | +DEFINE_EVENT(xe_pm_runtime, xe_pm_runtime_resume, | |
| 410 | + TP_PROTO(struct xe_device *xe, void *caller), | |
| 411 | + TP_ARGS(xe, caller) | |
| 412 | +); | |
| 413 | + | |
| 414 | +DEFINE_EVENT(xe_pm_runtime, xe_pm_runtime_suspend, | |
| 415 | + TP_PROTO(struct xe_device *xe, void *caller), | |
| 416 | + TP_ARGS(xe, caller) | |
| 417 | +); | |
| 418 | + | |
| 419 | +DEFINE_EVENT(xe_pm_runtime, xe_pm_runtime_get_ioctl, | |
| 420 | + TP_PROTO(struct xe_device *xe, void *caller), | |
| 421 | + TP_ARGS(xe, caller) | |
| 422 | +); | |
| 423 | + | |
| 372 | 424 | #endif |
| 373 | 425 | |
| 374 | 426 | /* This part must be outside protection */ |
| @@ -117,11 +117,6 @@ DEFINE_EVENT(xe_vma, xe_vma_acc, · 116 unmodified lines | ||
| 117 | 117 | TP_ARGS(vma) |
| 118 | 118 | ); |
| 119 | 119 | |
| 120 | −DEFINE_EVENT(xe_vma, xe_vma_fail, | |
| 121 | − TP_PROTO(struct xe_vma *vma), | |
| 122 | − TP_ARGS(vma) | |
| 123 | −); | |
| 124 | − | |
| 125 | 120 | DEFINE_EVENT(xe_vma, xe_vma_bind, |
| 126 | 121 | TP_PROTO(struct xe_vma *vma), |
| 127 | 122 | TP_ARGS(vma) |
| @@ -237,6 +232,11 @@ DEFINE_EVENT(xe_vm, xe_vm_rebind_worker_exit, · 109 unmodified lines | ||
| 237 | 232 | TP_ARGS(vm) |
| 238 | 233 | ); |
| 239 | 234 | |
| 235 | +DEFINE_EVENT(xe_vm, xe_vm_ops_fail, | |
| 236 | + TP_PROTO(struct xe_vm *vm), | |
| 237 | + TP_ARGS(vm) | |
| 238 | +); | |
| 239 | + | |
| 240 | 240 | #endif |
| 241 | 241 | |
| 242 | 242 | /* This part must be outside protection */ |
| @@ -93,6 +93,14 @@ static const struct xe_rtp_entry_sr lrc_tunings[] = { · 92 unmodified lines | ||
| 93 | 93 | REG_FIELD_PREP(L3_PWM_TIMER_INIT_VAL_MASK, 0x7f))) |
| 94 | 94 | }, |
| 95 | 95 | |
| 96 | + /* Xe2_HPG */ | |
| 97 | + | |
| 98 | + { XE_RTP_NAME("Tuning: vs hit max value"), | |
| 99 | + XE_RTP_RULES(GRAPHICS_VERSION(2001), ENGINE_CLASS(RENDER)), | |
| 100 | + XE_RTP_ACTIONS(FIELD_SET(FF_MODE, VS_HIT_MAX_VALUE_MASK, | |
| 101 | + REG_FIELD_PREP(VS_HIT_MAX_VALUE_MASK, 0x3f))) | |
| 102 | + }, | |
| 103 | + | |
| 96 | 104 | {} |
| 97 | 105 | }; |
| 98 | 106 | |
| @@ -116,6 +116,8 @@ struct fw_blobs_by_type { · 115 unmodified lines | ||
| 116 | 116 | fw_def(TIGERLAKE, major_ver(i915, guc, tgl, 70, 19, 2)) |
| 117 | 117 | |
| 118 | 118 | #define XE_HUC_FIRMWARE_DEFS(fw_def, mmp_ver, no_ver) \ |
| 119 | + fw_def(BATTLEMAGE, no_ver(xe, huc, bmg)) \ | |
| 120 | + fw_def(LUNARLAKE, no_ver(xe, huc, lnl)) \ | |
| 119 | 121 | fw_def(METEORLAKE, no_ver(i915, huc_gsc, mtl)) \ |
| 120 | 122 | fw_def(DG1, no_ver(i915, huc, dg1)) \ |
| 121 | 123 | fw_def(ALDERLAKE_P, no_ver(i915, huc, tgl)) \ |
| @@ -125,6 +127,7 @@ struct fw_blobs_by_type { · 3 unmodified lines | ||
| 125 | 127 | |
| 126 | 128 | /* for the GSC FW we match the compatibility version and not the release one */ |
| 127 | 129 | #define XE_GSC_FIRMWARE_DEFS(fw_def, major_ver) \ |
| 130 | + fw_def(LUNARLAKE, major_ver(xe, gsc, lnl, 1, 0, 0)) \ | |
| 128 | 131 | fw_def(METEORLAKE, major_ver(i915, gsc, mtl, 1, 0, 0)) |
| 129 | 132 | |
| 130 | 133 | #define MAKE_FW_PATH(dir__, uc__, shortname__, version__) \ |
| @@ -133,8 +133,10 @@ static int wait_for_existing_preempt_fences(struct xe_vm *vm) · 132 unmodified lines | ||
| 133 | 133 | if (q->lr.pfence) { |
| 134 | 134 | long timeout = dma_fence_wait(q->lr.pfence, false); |
| 135 | 135 | |
| 136 | − if (timeout < 0) | |
| 136 | + /* Only -ETIME on fence indicates VM needs to be killed */ | |
| 137 | + if (timeout < 0 || q->lr.pfence->error == -ETIME) | |
| 137 | 138 | return -ETIME; |
| 139 | + | |
| 138 | 140 | dma_fence_put(q->lr.pfence); |
| 139 | 141 | q->lr.pfence = NULL; |
| 140 | 142 | } |
| @@ -311,7 +313,15 @@ int __xe_vm_userptr_needs_repin(struct xe_vm *vm) · 170 unmodified lines | ||
| 311 | 313 | |
| 312 | 314 | #define XE_VM_REBIND_RETRY_TIMEOUT_MS 1000 |
| 313 | 315 | |
| 314 | −static void xe_vm_kill(struct xe_vm *vm, bool unlocked) | |
| 316 | +/** | |
| 317 | + * xe_vm_kill() - VM Kill | |
| 318 | + * @vm: The VM. | |
| 319 | + * @unlocked: Flag indicates the VM's dma-resv is not held | |
| 320 | + * | |
| 321 | + * Kill the VM by setting banned flag indicated VM is no longer available for | |
| 322 | + * use. If in preempt fence mode, also kill all exec queue attached to the VM. | |
| 323 | + */ | |
| 324 | +void xe_vm_kill(struct xe_vm *vm, bool unlocked) | |
| 315 | 325 | { |
| 316 | 326 | struct xe_exec_queue *q; |
| 317 | 327 | |
| @@ -708,6 +718,42 @@ int xe_vm_userptr_check_repin(struct xe_vm *vm) · 390 unmodified lines | ||
| 708 | 718 | list_empty_careful(&vm->userptr.invalidated)) ? 0 : -EAGAIN; |
| 709 | 719 | } |
| 710 | 720 | |
| 721 | +static int xe_vma_ops_alloc(struct xe_vma_ops *vops, bool array_of_binds) | |
| 722 | +{ | |
| 723 | + int i; | |
| 724 | + | |
| 725 | + for (i = 0; i < XE_MAX_TILES_PER_DEVICE; ++i) { | |
| 726 | + if (!vops->pt_update_ops[i].num_ops) | |
| 727 | + continue; | |
| 728 | + | |
| 729 | + vops->pt_update_ops[i].ops = | |
| 730 | + kmalloc_array(vops->pt_update_ops[i].num_ops, | |
| 731 | + sizeof(*vops->pt_update_ops[i].ops), | |
| 732 | + GFP_KERNEL); | |
| 733 | + if (!vops->pt_update_ops[i].ops) | |
| 734 | + return array_of_binds ? -ENOBUFS : -ENOMEM; | |
| 735 | + } | |
| 736 | + | |
| 737 | + return 0; | |
| 738 | +} | |
| 739 | + | |
| 740 | +static void xe_vma_ops_fini(struct xe_vma_ops *vops) | |
| 741 | +{ | |
| 742 | + int i; | |
| 743 | + | |
| 744 | + for (i = 0; i < XE_MAX_TILES_PER_DEVICE; ++i) | |
| 745 | + kfree(vops->pt_update_ops[i].ops); | |
| 746 | +} | |
| 747 | + | |
| 748 | +static void xe_vma_ops_incr_pt_update_ops(struct xe_vma_ops *vops, u8 tile_mask) | |
| 749 | +{ | |
| 750 | + int i; | |
| 751 | + | |
| 752 | + for (i = 0; i < XE_MAX_TILES_PER_DEVICE; ++i) | |
| 753 | + if (BIT(i) & tile_mask) | |
| 754 | + ++vops->pt_update_ops[i].num_ops; | |
| 755 | +} | |
| 756 | + | |
| 711 | 757 | static void xe_vm_populate_rebind(struct xe_vma_op *op, struct xe_vma *vma, |
| 712 | 758 | u8 tile_mask) |
| 713 | 759 | { |
| @@ -735,6 +781,7 @@ static int xe_vm_ops_add_rebind(struct xe_vma_ops *vops, struct xe_vma *vma, · 21 unmodified lines | ||
| 735 | 781 | |
| 736 | 782 | xe_vm_populate_rebind(op, vma, tile_mask); |
| 737 | 783 | list_add_tail(&op->link, &vops->list); |
| 784 | + xe_vma_ops_incr_pt_update_ops(vops, tile_mask); | |
| 738 | 785 | |
| 739 | 786 | return 0; |
| 740 | 787 | } |
| @@ -751,7 +798,7 @@ int xe_vm_rebind(struct xe_vm *vm, bool rebind_worker) · 10 unmodified lines | ||
| 751 | 798 | struct xe_vma *vma, *next; |
| 752 | 799 | struct xe_vma_ops vops; |
| 753 | 800 | struct xe_vma_op *op, *next_op; |
| 754 | − int err; | |
| 801 | + int err, i; | |
| 755 | 802 | |
| 756 | 803 | lockdep_assert_held(&vm->lock); |
| 757 | 804 | if ((xe_vm_in_lr_mode(vm) && !rebind_worker) || |
| @@ -759,6 +806,8 @@ int xe_vm_rebind(struct xe_vm *vm, bool rebind_worker) · 1 unmodified line | ||
| 759 | 806 | return 0; |
| 760 | 807 | |
| 761 | 808 | xe_vma_ops_init(&vops, vm, NULL, NULL, 0); |
| 809 | + for (i = 0; i < XE_MAX_TILES_PER_DEVICE; ++i) | |
| 810 | + vops.pt_update_ops[i].wait_vm_bookkeep = true; | |
| 762 | 811 | |
| 763 | 812 | xe_vm_assert_held(vm); |
| 764 | 813 | list_for_each_entry(vma, &vm->rebind_list, combined_links.rebind) { |
| @@ -775,6 +824,10 @@ int xe_vm_rebind(struct xe_vm *vm, bool rebind_worker) · 10 unmodified lines | ||
| 775 | 824 | goto free_ops; |
| 776 | 825 | } |
| 777 | 826 | |
| 827 | + err = xe_vma_ops_alloc(&vops, false); | |
| 828 | + if (err) | |
| 829 | + goto free_ops; | |
| 830 | + | |
| 778 | 831 | fence = ops_execute(vm, &vops); |
| 779 | 832 | if (IS_ERR(fence)) { |
| 780 | 833 | err = PTR_ERR(fence); |
| @@ -789,6 +842,7 @@ free_ops: · 8 unmodified lines | ||
| 789 | 842 | list_del(&op->link); |
| 790 | 843 | kfree(op); |
| 791 | 844 | } |
| 845 | + xe_vma_ops_fini(&vops); | |
| 792 | 846 | |
| 793 | 847 | return err; |
| 794 | 848 | } |
| @@ -798,6 +852,8 @@ struct dma_fence *xe_vma_rebind(struct xe_vm *vm, struct xe_vma *vma, u8 tile_ma · 3 unmodified lines | ||
| 798 | 852 | struct dma_fence *fence = NULL; |
| 799 | 853 | struct xe_vma_ops vops; |
| 800 | 854 | struct xe_vma_op *op, *next_op; |
| 855 | + struct xe_tile *tile; | |
| 856 | + u8 id; | |
| 801 | 857 | int err; |
| 802 | 858 | |
| 803 | 859 | lockdep_assert_held(&vm->lock); |
| @@ -805,17 +861,30 @@ struct dma_fence *xe_vma_rebind(struct xe_vm *vm, struct xe_vma *vma, u8 tile_ma · 1 unmodified line | ||
| 805 | 861 | xe_assert(vm->xe, xe_vm_in_fault_mode(vm)); |
| 806 | 862 | |
| 807 | 863 | xe_vma_ops_init(&vops, vm, NULL, NULL, 0); |
| 864 | + for_each_tile(tile, vm->xe, id) { | |
| 865 | + vops.pt_update_ops[id].wait_vm_bookkeep = true; | |
| 866 | + vops.pt_update_ops[tile->id].q = | |
| 867 | + xe_tile_migrate_exec_queue(tile); | |
| 868 | + } | |
| 808 | 869 | |
| 809 | 870 | err = xe_vm_ops_add_rebind(&vops, vma, tile_mask); |
| 810 | 871 | if (err) |
| 811 | 872 | return ERR_PTR(err); |
| 812 | 873 | |
| 874 | + err = xe_vma_ops_alloc(&vops, false); | |
| 875 | + if (err) { | |
| 876 | + fence = ERR_PTR(err); | |
| 877 | + goto free_ops; | |
| 878 | + } | |
| 879 | + | |
| 813 | 880 | fence = ops_execute(vm, &vops); |
| 814 | 881 | |
| 882 | +free_ops: | |
| 815 | 883 | list_for_each_entry_safe(op, next_op, &vops.list, link) { |
| 816 | 884 | list_del(&op->link); |
| 817 | 885 | kfree(op); |
| 818 | 886 | } |
| 887 | + xe_vma_ops_fini(&vops); | |
| 819 | 888 | |
| 820 | 889 | return fence; |
| 821 | 890 | } |
| @@ -1601,6 +1670,10 @@ static void vm_destroy_work_func(struct work_struct *w) · 779 unmodified lines | ||
| 1601 | 1670 | XE_WARN_ON(vm->pt_root[id]); |
| 1602 | 1671 | |
| 1603 | 1672 | trace_xe_vm_free(vm); |
| 1673 | + | |
| 1674 | + if (vm->xef) | |
| 1675 | + xe_file_put(vm->xef); | |
| 1676 | + | |
| 1604 | 1677 | kfree(vm); |
| 1605 | 1678 | } |
| 1606 | 1679 | |
| @@ -1637,147 +1710,6 @@ to_wait_exec_queue(struct xe_vm *vm, struct xe_exec_queue *q) · 30 unmodified lines | ||
| 1637 | 1710 | return q ? q : vm->q[0]; |
| 1638 | 1711 | } |
| 1639 | 1712 | |
| 1640 | −static struct dma_fence * | |
| 1641 | −xe_vm_unbind_vma(struct xe_vma *vma, struct xe_exec_queue *q, | |
| 1642 | − struct xe_sync_entry *syncs, u32 num_syncs, | |
| 1643 | − bool first_op, bool last_op) | |
| 1644 | −{ | |
| 1645 | − struct xe_vm *vm = xe_vma_vm(vma); | |
| 1646 | − struct xe_exec_queue *wait_exec_queue = to_wait_exec_queue(vm, q); | |
| 1647 | − struct xe_tile *tile; | |
| 1648 | − struct dma_fence *fence = NULL; | |
| 1649 | − struct dma_fence **fences = NULL; | |
| 1650 | − struct dma_fence_array *cf = NULL; | |
| 1651 | − int cur_fence = 0; | |
| 1652 | − int number_tiles = hweight8(vma->tile_present); | |
| 1653 | − int err; | |
| 1654 | − u8 id; | |
| 1655 | − | |
| 1656 | − trace_xe_vma_unbind(vma); | |
| 1657 | − | |
| 1658 | − if (number_tiles > 1) { | |
| 1659 | − fences = kmalloc_array(number_tiles, sizeof(*fences), | |
| 1660 | − GFP_KERNEL); | |
| 1661 | − if (!fences) | |
| 1662 | − return ERR_PTR(-ENOMEM); | |
| 1663 | − } | |
| 1664 | − | |
| 1665 | − for_each_tile(tile, vm->xe, id) { | |
| 1666 | − if (!(vma->tile_present & BIT(id))) | |
| 1667 | − goto next; | |
| 1668 | − | |
| 1669 | − fence = __xe_pt_unbind_vma(tile, vma, q ? q : vm->q[id], | |
| 1670 | − first_op ? syncs : NULL, | |
| 1671 | − first_op ? num_syncs : 0); | |
| 1672 | − if (IS_ERR(fence)) { | |
| 1673 | − err = PTR_ERR(fence); | |
| 1674 | − goto err_fences; | |
| 1675 | − } | |
| 1676 | − | |
| 1677 | − if (fences) | |
| 1678 | − fences[cur_fence++] = fence; | |
| 1679 | − | |
| 1680 | −next: | |
| 1681 | − if (q && vm->pt_root[id] && !list_empty(&q->multi_gt_list)) | |
| 1682 | − q = list_next_entry(q, multi_gt_list); | |
| 1683 | − } | |
| 1684 | − | |
| 1685 | − if (fences) { | |
| 1686 | − cf = dma_fence_array_create(number_tiles, fences, | |
| 1687 | − vm->composite_fence_ctx, | |
| 1688 | − vm->composite_fence_seqno++, | |
| 1689 | − false); | |
| 1690 | − if (!cf) { | |
| 1691 | − --vm->composite_fence_seqno; | |
| 1692 | − err = -ENOMEM; | |
| 1693 | − goto err_fences; | |
| 1694 | − } | |
| 1695 | − } | |
| 1696 | − | |
| 1697 | − fence = cf ? &cf->base : !fence ? | |
| 1698 | − xe_exec_queue_last_fence_get(wait_exec_queue, vm) : fence; | |
| 1699 | − | |
| 1700 | − return fence; | |
| 1701 | − | |
| 1702 | −err_fences: | |
| 1703 | − if (fences) { | |
| 1704 | − while (cur_fence) | |
| 1705 | − dma_fence_put(fences[--cur_fence]); | |
| 1706 | − kfree(fences); | |
| 1707 | − } | |
| 1708 | − | |
| 1709 | − return ERR_PTR(err); | |
| 1710 | −} | |
| 1711 | − | |
| 1712 | −static struct dma_fence * | |
| 1713 | −xe_vm_bind_vma(struct xe_vma *vma, struct xe_exec_queue *q, | |
| 1714 | − struct xe_sync_entry *syncs, u32 num_syncs, | |
| 1715 | − u8 tile_mask, bool first_op, bool last_op) | |
| 1716 | −{ | |
| 1717 | − struct xe_tile *tile; | |
| 1718 | − struct dma_fence *fence; | |
| 1719 | − struct dma_fence **fences = NULL; | |
| 1720 | − struct dma_fence_array *cf = NULL; | |
| 1721 | − struct xe_vm *vm = xe_vma_vm(vma); | |
| 1722 | − int cur_fence = 0; | |
| 1723 | − int number_tiles = hweight8(tile_mask); | |
| 1724 | − int err; | |
| 1725 | − u8 id; | |
| 1726 | − | |
| 1727 | − trace_xe_vma_bind(vma); | |
| 1728 | − | |
| 1729 | − if (number_tiles > 1) { | |
| 1730 | − fences = kmalloc_array(number_tiles, sizeof(*fences), | |
| 1731 | − GFP_KERNEL); | |
| 1732 | − if (!fences) | |
| 1733 | − return ERR_PTR(-ENOMEM); | |
| 1734 | − } | |
| 1735 | − | |
| 1736 | − for_each_tile(tile, vm->xe, id) { | |
| 1737 | − if (!(tile_mask & BIT(id))) | |
| 1738 | − goto next; | |
| 1739 | − | |
| 1740 | − fence = __xe_pt_bind_vma(tile, vma, q ? q : vm->q[id], | |
| 1741 | − first_op ? syncs : NULL, | |
| 1742 | − first_op ? num_syncs : 0, | |
| 1743 | − vma->tile_present & BIT(id)); | |
| 1744 | − if (IS_ERR(fence)) { | |
| 1745 | − err = PTR_ERR(fence); | |
| 1746 | − goto err_fences; | |
| 1747 | − } | |
| 1748 | − | |
| 1749 | − if (fences) | |
| 1750 | − fences[cur_fence++] = fence; | |
| 1751 | − | |
| 1752 | −next: | |
| 1753 | − if (q && vm->pt_root[id] && !list_empty(&q->multi_gt_list)) | |
| 1754 | − q = list_next_entry(q, multi_gt_list); | |
| 1755 | − } | |
| 1756 | − | |
| 1757 | − if (fences) { | |
| 1758 | − cf = dma_fence_array_create(number_tiles, fences, | |
| 1759 | − vm->composite_fence_ctx, | |
| 1760 | − vm->composite_fence_seqno++, | |
| 1761 | − false); | |
| 1762 | − if (!cf) { | |
| 1763 | − --vm->composite_fence_seqno; | |
| 1764 | − err = -ENOMEM; | |
| 1765 | − goto err_fences; | |
| 1766 | − } | |
| 1767 | − } | |
| 1768 | − | |
| 1769 | − return cf ? &cf->base : fence; | |
| 1770 | − | |
| 1771 | −err_fences: | |
| 1772 | − if (fences) { | |
| 1773 | − while (cur_fence) | |
| 1774 | − dma_fence_put(fences[--cur_fence]); | |
| 1775 | − kfree(fences); | |
| 1776 | − } | |
| 1777 | − | |
| 1778 | − return ERR_PTR(err); | |
| 1779 | −} | |
| 1780 | − | |
| 1781 | 1713 | static struct xe_user_fence * |
| 1782 | 1714 | find_ufence_get(struct xe_sync_entry *syncs, u32 num_syncs) |
| 1783 | 1715 | { |
| @@ -1793,48 +1725,6 @@ find_ufence_get(struct xe_sync_entry *syncs, u32 num_syncs) · 9 unmodified lines | ||
| 1793 | 1725 | return NULL; |
| 1794 | 1726 | } |
| 1795 | 1727 | |
| 1796 | −static struct dma_fence * | |
| 1797 | −xe_vm_bind(struct xe_vm *vm, struct xe_vma *vma, struct xe_exec_queue *q, | |
| 1798 | − struct xe_bo *bo, struct xe_sync_entry *syncs, u32 num_syncs, | |
| 1799 | − u8 tile_mask, bool immediate, bool first_op, bool last_op) | |
| 1800 | −{ | |
| 1801 | − struct dma_fence *fence; | |
| 1802 | − struct xe_exec_queue *wait_exec_queue = to_wait_exec_queue(vm, q); | |
| 1803 | − | |
| 1804 | − xe_vm_assert_held(vm); | |
| 1805 | − xe_bo_assert_held(bo); | |
| 1806 | − | |
| 1807 | − if (immediate) { | |
| 1808 | − fence = xe_vm_bind_vma(vma, q, syncs, num_syncs, tile_mask, | |
| 1809 | − first_op, last_op); | |
| 1810 | − if (IS_ERR(fence)) | |
| 1811 | − return fence; | |
| 1812 | − } else { | |
| 1813 | − xe_assert(vm->xe, xe_vm_in_fault_mode(vm)); | |
| 1814 | − | |
| 1815 | − fence = xe_exec_queue_last_fence_get(wait_exec_queue, vm); | |
| 1816 | − } | |
| 1817 | − | |
| 1818 | − return fence; | |
| 1819 | −} | |
| 1820 | − | |
| 1821 | −static struct dma_fence * | |
| 1822 | −xe_vm_unbind(struct xe_vm *vm, struct xe_vma *vma, | |
| 1823 | − struct xe_exec_queue *q, struct xe_sync_entry *syncs, | |
| 1824 | − u32 num_syncs, bool first_op, bool last_op) | |
| 1825 | −{ | |
| 1826 | − struct dma_fence *fence; | |
| 1827 | − | |
| 1828 | − xe_vm_assert_held(vm); | |
| 1829 | − xe_bo_assert_held(xe_vma_bo(vma)); | |
| 1830 | − | |
| 1831 | − fence = xe_vm_unbind_vma(vma, q, syncs, num_syncs, first_op, last_op); | |
| 1832 | − if (IS_ERR(fence)) | |
| 1833 | − return fence; | |
| 1834 | − | |
| 1835 | − return fence; | |
| 1836 | −} | |
| 1837 | − | |
| 1838 | 1728 | #define ALL_DRM_XE_VM_CREATE_FLAGS (DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE | \ |
| 1839 | 1729 | DRM_XE_VM_CREATE_FLAG_LR_MODE | \ |
| 1840 | 1730 | DRM_XE_VM_CREATE_FLAG_FAULT_MODE) |
| @@ -1916,7 +1806,7 @@ int xe_vm_create_ioctl(struct drm_device *dev, void *data, · 75 unmodified lines | ||
| 1916 | 1806 | } |
| 1917 | 1807 | |
| 1918 | 1808 | args->vm_id = id; |
| 1919 | − vm->xef = xef; | |
| 1809 | + vm->xef = xe_file_get(xef); | |
| 1920 | 1810 | |
| 1921 | 1811 | /* Record BO memory for VM pagetable created against client */ |
| 1922 | 1812 | for_each_tile(tile, xe, id) |
| @@ -1975,21 +1865,6 @@ static const u32 region_to_mem_type[] = { · 52 unmodified lines | ||
| 1975 | 1865 | XE_PL_VRAM1, |
| 1976 | 1866 | }; |
| 1977 | 1867 | |
| 1978 | −static struct dma_fence * | |
| 1979 | −xe_vm_prefetch(struct xe_vm *vm, struct xe_vma *vma, | |
| 1980 | − struct xe_exec_queue *q, struct xe_sync_entry *syncs, | |
| 1981 | − u32 num_syncs, bool first_op, bool last_op) | |
| 1982 | −{ | |
| 1983 | − struct xe_exec_queue *wait_exec_queue = to_wait_exec_queue(vm, q); | |
| 1984 | − | |
| 1985 | − if (vma->tile_mask != (vma->tile_present & ~vma->tile_invalidated)) { | |
| 1986 | − return xe_vm_bind(vm, vma, q, xe_vma_bo(vma), syncs, num_syncs, | |
| 1987 | − vma->tile_mask, true, first_op, last_op); | |
| 1988 | − } else { | |
| 1989 | − return xe_exec_queue_last_fence_get(wait_exec_queue, vm); | |
| 1990 | − } | |
| 1991 | −} | |
| 1992 | − | |
| 1993 | 1868 | static void prep_vma_destroy(struct xe_vm *vm, struct xe_vma *vma, |
| 1994 | 1869 | bool post_commit) |
| 1995 | 1870 | { |
| @@ -2277,14 +2152,10 @@ static int xe_vma_op_commit(struct xe_vm *vm, struct xe_vma_op *op) · 281 unmodified lines | ||
| 2277 | 2152 | return err; |
| 2278 | 2153 | } |
| 2279 | 2154 | |
| 2280 | − | |
| 2281 | −static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct xe_exec_queue *q, | |
| 2282 | − struct drm_gpuva_ops *ops, | |
| 2283 | − struct xe_sync_entry *syncs, u32 num_syncs, | |
| 2284 | − struct xe_vma_ops *vops, bool last) | |
| 2155 | +static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops, | |
| 2156 | + struct xe_vma_ops *vops) | |
| 2285 | 2157 | { |
| 2286 | 2158 | struct xe_device *xe = vm->xe; |
| 2287 | − struct xe_vma_op *last_op = NULL; | |
| 2288 | 2159 | struct drm_gpuva_op *__op; |
| 2289 | 2160 | struct xe_tile *tile; |
| 2290 | 2161 | u8 id, tile_mask = 0; |
| @@ -2298,19 +2169,10 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct xe_exec_queue *q, · 7 unmodified lines | ||
| 2298 | 2169 | drm_gpuva_for_each_op(__op, ops) { |
| 2299 | 2170 | struct xe_vma_op *op = gpuva_op_to_vma_op(__op); |
| 2300 | 2171 | struct xe_vma *vma; |
| 2301 | − bool first = list_empty(&vops->list); | |
| 2302 | 2172 | unsigned int flags = 0; |
| 2303 | 2173 | |
| 2304 | 2174 | INIT_LIST_HEAD(&op->link); |
| 2305 | 2175 | list_add_tail(&op->link, &vops->list); |
| 2306 | − | |
| 2307 | − if (first) { | |
| 2308 | − op->flags |= XE_VMA_OP_FIRST; | |
| 2309 | − op->num_syncs = num_syncs; | |
| 2310 | − op->syncs = syncs; | |
| 2311 | − } | |
| 2312 | − | |
| 2313 | − op->q = q; | |
| 2314 | 2176 | op->tile_mask = tile_mask; |
| 2315 | 2177 | |
| 2316 | 2178 | switch (op->base.op) { |
| @@ -2329,6 +2191,9 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct xe_exec_queue *q, · 12 unmodified lines | ||
| 2329 | 2191 | return PTR_ERR(vma); |
| 2330 | 2192 | |
| 2331 | 2193 | op->map.vma = vma; |
| 2194 | + if (op->map.immediate || !xe_vm_in_fault_mode(vm)) | |
| 2195 | + xe_vma_ops_incr_pt_update_ops(vops, | |
| 2196 | + op->tile_mask); | |
| 2332 | 2197 | break; |
| 2333 | 2198 | } |
| 2334 | 2199 | case DRM_GPUVA_OP_REMAP: |
| @@ -2373,6 +2238,8 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct xe_exec_queue *q, · 38 unmodified lines | ||
| 2373 | 2238 | vm_dbg(&xe->drm, "REMAP:SKIP_PREV: addr=0x%016llx, range=0x%016llx", |
| 2374 | 2239 | (ULL)op->remap.start, |
| 2375 | 2240 | (ULL)op->remap.range); |
| 2241 | + } else { | |
| 2242 | + xe_vma_ops_incr_pt_update_ops(vops, op->tile_mask); | |
| 2376 | 2243 | } |
| 2377 | 2244 | } |
| 2378 | 2245 | |
| @@ -2409,203 +2276,30 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct xe_exec_queue *q, · 30 unmodified lines | ||
| 2409 | 2276 | vm_dbg(&xe->drm, "REMAP:SKIP_NEXT: addr=0x%016llx, range=0x%016llx", |
| 2410 | 2277 | (ULL)op->remap.start, |
| 2411 | 2278 | (ULL)op->remap.range); |
| 2279 | + } else { | |
| 2280 | + xe_vma_ops_incr_pt_update_ops(vops, op->tile_mask); | |
| 2412 | 2281 | } |
| 2413 | 2282 | } |
| 2283 | + xe_vma_ops_incr_pt_update_ops(vops, op->tile_mask); | |
| 2414 | 2284 | break; |
| 2415 | 2285 | } |
| 2416 | 2286 | case DRM_GPUVA_OP_UNMAP: |
| 2417 | 2287 | case DRM_GPUVA_OP_PREFETCH: |
| 2418 | − /* Nothing to do */ | |
| 2288 | + /* FIXME: Need to skip some prefetch ops */ | |
| 2289 | + xe_vma_ops_incr_pt_update_ops(vops, op->tile_mask); | |
| 2419 | 2290 | break; |
| 2420 | 2291 | default: |
| 2421 | 2292 | drm_warn(&vm->xe->drm, "NOT POSSIBLE"); |
| 2422 | 2293 | } |
| 2423 | 2294 | |
| 2424 | − last_op = op; | |
| 2425 | − | |
| 2426 | 2295 | err = xe_vma_op_commit(vm, op); |
| 2427 | 2296 | if (err) |
| 2428 | 2297 | return err; |
| 2429 | 2298 | } |
| 2430 | 2299 | |
| 2431 | − /* FIXME: Unhandled corner case */ | |
| 2432 | − XE_WARN_ON(!last_op && last && !list_empty(&vops->list)); | |
| 2433 | − | |
| 2434 | − if (!last_op) | |
| 2435 | − return 0; | |
| 2436 | − | |
| 2437 | − if (last) { | |
| 2438 | − last_op->flags |= XE_VMA_OP_LAST; | |
| 2439 | − last_op->num_syncs = num_syncs; | |
| 2440 | − last_op->syncs = syncs; | |
| 2441 | − } | |
| 2442 | − | |
| 2443 | 2300 | return 0; |
| 2444 | 2301 | } |
| 2445 | 2302 | |
| 2446 | −static struct dma_fence *op_execute(struct xe_vm *vm, struct xe_vma *vma, | |
| 2447 | − struct xe_vma_op *op) | |
| 2448 | −{ | |
| 2449 | − struct dma_fence *fence = NULL; | |
| 2450 | − | |
| 2451 | − lockdep_assert_held(&vm->lock); | |
| 2452 | − | |
| 2453 | − xe_vm_assert_held(vm); | |
| 2454 | − xe_bo_assert_held(xe_vma_bo(vma)); | |
| 2455 | − | |
| 2456 | − switch (op->base.op) { | |
| 2457 | − case DRM_GPUVA_OP_MAP: | |
| 2458 | − fence = xe_vm_bind(vm, vma, op->q, xe_vma_bo(vma), | |
| 2459 | − op->syncs, op->num_syncs, | |
| 2460 | − op->tile_mask, | |
| 2461 | − op->map.immediate || !xe_vm_in_fault_mode(vm), | |
| 2462 | − op->flags & XE_VMA_OP_FIRST, | |
| 2463 | − op->flags & XE_VMA_OP_LAST); | |
| 2464 | − break; | |
| 2465 | − case DRM_GPUVA_OP_REMAP: | |
| 2466 | − { | |
| 2467 | − bool prev = !!op->remap.prev; | |
| 2468 | − bool next = !!op->remap.next; | |
| 2469 | − | |
| 2470 | − if (!op->remap.unmap_done) { | |
| 2471 | − if (prev || next) | |
| 2472 | − vma->gpuva.flags |= XE_VMA_FIRST_REBIND; | |
| 2473 | − fence = xe_vm_unbind(vm, vma, op->q, op->syncs, | |
| 2474 | − op->num_syncs, | |
| 2475 | − op->flags & XE_VMA_OP_FIRST, | |
| 2476 | − op->flags & XE_VMA_OP_LAST && | |
| 2477 | − !prev && !next); | |
| 2478 | − if (IS_ERR(fence)) | |
| 2479 | − break; | |
| 2480 | − op->remap.unmap_done = true; | |
| 2481 | − } | |
| 2482 | − | |
| 2483 | − if (prev) { | |
| 2484 | − op->remap.prev->gpuva.flags |= XE_VMA_LAST_REBIND; | |
| 2485 | − dma_fence_put(fence); | |
| 2486 | − fence = xe_vm_bind(vm, op->remap.prev, op->q, | |
| 2487 | − xe_vma_bo(op->remap.prev), op->syncs, | |
| 2488 | − op->num_syncs, | |
| 2489 | − op->remap.prev->tile_mask, true, | |
| 2490 | − false, | |
| 2491 | − op->flags & XE_VMA_OP_LAST && !next); | |
| 2492 | − op->remap.prev->gpuva.flags &= ~XE_VMA_LAST_REBIND; | |
| 2493 | − if (IS_ERR(fence)) | |
| 2494 | − break; | |
| 2495 | − op->remap.prev = NULL; | |
| 2496 | − } | |
| 2497 | − | |
| 2498 | − if (next) { | |
| 2499 | − op->remap.next->gpuva.flags |= XE_VMA_LAST_REBIND; | |
| 2500 | − dma_fence_put(fence); | |
| 2501 | − fence = xe_vm_bind(vm, op->remap.next, op->q, | |
| 2502 | − xe_vma_bo(op->remap.next), | |
| 2503 | − op->syncs, op->num_syncs, | |
| 2504 | − op->remap.next->tile_mask, true, | |
| 2505 | − false, op->flags & XE_VMA_OP_LAST); | |
| 2506 | − op->remap.next->gpuva.flags &= ~XE_VMA_LAST_REBIND; | |
| 2507 | − if (IS_ERR(fence)) | |
| 2508 | − break; | |
| 2509 | − op->remap.next = NULL; | |
| 2510 | − } | |
| 2511 | − | |
| 2512 | − break; | |
| 2513 | − } | |
| 2514 | − case DRM_GPUVA_OP_UNMAP: | |
| 2515 | − fence = xe_vm_unbind(vm, vma, op->q, op->syncs, | |
| 2516 | − op->num_syncs, op->flags & XE_VMA_OP_FIRST, | |
| 2517 | − op->flags & XE_VMA_OP_LAST); | |
| 2518 | − break; | |
| 2519 | − case DRM_GPUVA_OP_PREFETCH: | |
| 2520 | − fence = xe_vm_prefetch(vm, vma, op->q, op->syncs, op->num_syncs, | |
| 2521 | − op->flags & XE_VMA_OP_FIRST, | |
| 2522 | − op->flags & XE_VMA_OP_LAST); | |
| 2523 | − break; | |
| 2524 | − default: | |
| 2525 | − drm_warn(&vm->xe->drm, "NOT POSSIBLE"); | |
| 2526 | − } | |
| 2527 | − | |
| 2528 | − if (IS_ERR(fence)) | |
| 2529 | − trace_xe_vma_fail(vma); | |
| 2530 | − | |
| 2531 | − return fence; | |
| 2532 | −} | |
| 2533 | − | |
| 2534 | −static struct dma_fence * | |
| 2535 | −__xe_vma_op_execute(struct xe_vm *vm, struct xe_vma *vma, | |
| 2536 | − struct xe_vma_op *op) | |
| 2537 | −{ | |
| 2538 | − struct dma_fence *fence; | |
| 2539 | − int err; | |
| 2540 | − | |
| 2541 | −retry_userptr: | |
| 2542 | − fence = op_execute(vm, vma, op); | |
| 2543 | − if (IS_ERR(fence) && PTR_ERR(fence) == -EAGAIN) { | |
| 2544 | − lockdep_assert_held_write(&vm->lock); | |
| 2545 | − | |
| 2546 | − if (op->base.op == DRM_GPUVA_OP_REMAP) { | |
| 2547 | − if (!op->remap.unmap_done) | |
| 2548 | − vma = gpuva_to_vma(op->base.remap.unmap->va); | |
| 2549 | − else if (op->remap.prev) | |
| 2550 | − vma = op->remap.prev; | |
| 2551 | − else | |
| 2552 | − vma = op->remap.next; | |
| 2553 | − } | |
| 2554 | − | |
| 2555 | − if (xe_vma_is_userptr(vma)) { | |
| 2556 | − err = xe_vma_userptr_pin_pages(to_userptr_vma(vma)); | |
| 2557 | − if (!err) | |
| 2558 | − goto retry_userptr; | |
| 2559 | − | |
| 2560 | − fence = ERR_PTR(err); | |
| 2561 | − trace_xe_vma_fail(vma); | |
| 2562 | − } | |
| 2563 | − } | |
| 2564 | − | |
| 2565 | − return fence; | |
| 2566 | −} | |
| 2567 | − | |
| 2568 | −static struct dma_fence * | |
| 2569 | −xe_vma_op_execute(struct xe_vm *vm, struct xe_vma_op *op) | |
| 2570 | −{ | |
| 2571 | − struct dma_fence *fence = ERR_PTR(-ENOMEM); | |
| 2572 | − | |
| 2573 | − lockdep_assert_held(&vm->lock); | |
| 2574 | − | |
| 2575 | − switch (op->base.op) { | |
| 2576 | − case DRM_GPUVA_OP_MAP: | |
| 2577 | − fence = __xe_vma_op_execute(vm, op->map.vma, op); | |
| 2578 | − break; | |
| 2579 | − case DRM_GPUVA_OP_REMAP: | |
| 2580 | − { | |
| 2581 | − struct xe_vma *vma; | |
| 2582 | − | |
| 2583 | − if (!op->remap.unmap_done) | |
| 2584 | − vma = gpuva_to_vma(op->base.remap.unmap->va); | |
| 2585 | − else if (op->remap.prev) | |
| 2586 | − vma = op->remap.prev; | |
| 2587 | − else | |
| 2588 | − vma = op->remap.next; | |
| 2589 | − | |
| 2590 | − fence = __xe_vma_op_execute(vm, vma, op); | |
| 2591 | − break; | |
| 2592 | − } | |
| 2593 | − case DRM_GPUVA_OP_UNMAP: | |
| 2594 | − fence = __xe_vma_op_execute(vm, gpuva_to_vma(op->base.unmap.va), | |
| 2595 | − op); | |
| 2596 | − break; | |
| 2597 | − case DRM_GPUVA_OP_PREFETCH: | |
| 2598 | − fence = __xe_vma_op_execute(vm, | |
| 2599 | − gpuva_to_vma(op->base.prefetch.va), | |
| 2600 | − op); | |
| 2601 | − break; | |
| 2602 | − default: | |
| 2603 | − drm_warn(&vm->xe->drm, "NOT POSSIBLE"); | |
| 2604 | − } | |
| 2605 | − | |
| 2606 | − return fence; | |
| 2607 | −} | |
| 2608 | − | |
| 2609 | 2303 | static void xe_vma_op_unwind(struct xe_vm *vm, struct xe_vma_op *op, |
| 2610 | 2304 | bool post_commit, bool prev_post_commit, |
| 2611 | 2305 | bool next_post_commit) |
| @@ -2788,26 +2482,157 @@ static int vm_bind_ioctl_ops_lock_and_prep(struct drm_exec *exec, · 176 unmodified lines | ||
| 2788 | 2482 | return err; |
| 2789 | 2483 | } |
| 2790 | 2484 | |
| 2485 | +#ifdef TEST_VM_OPS_ERROR | |
| 2486 | + if (vops->inject_error && | |
| 2487 | + vm->xe->vm_inject_error_position == FORCE_OP_ERROR_LOCK) | |
| 2488 | + return -ENOSPC; | |
| 2489 | +#endif | |
| 2490 | + | |
| 2791 | 2491 | return 0; |
| 2792 | 2492 | } |
| 2793 | 2493 | |
| 2494 | +static void op_trace(struct xe_vma_op *op) | |
| 2495 | +{ | |
| 2496 | + switch (op->base.op) { | |
| 2497 | + case DRM_GPUVA_OP_MAP: | |
| 2498 | + trace_xe_vma_bind(op->map.vma); | |
| 2499 | + break; | |
| 2500 | + case DRM_GPUVA_OP_REMAP: | |
| 2501 | + trace_xe_vma_unbind(gpuva_to_vma(op->base.remap.unmap->va)); | |
| 2502 | + if (op->remap.prev) | |
| 2503 | + trace_xe_vma_bind(op->remap.prev); | |
| 2504 | + if (op->remap.next) | |
| 2505 | + trace_xe_vma_bind(op->remap.next); | |
| 2506 | + break; | |
| 2507 | + case DRM_GPUVA_OP_UNMAP: | |
| 2508 | + trace_xe_vma_unbind(gpuva_to_vma(op->base.unmap.va)); | |
| 2509 | + break; | |
| 2510 | + case DRM_GPUVA_OP_PREFETCH: | |
| 2511 | + trace_xe_vma_bind(gpuva_to_vma(op->base.prefetch.va)); | |
| 2512 | + break; | |
| 2513 | + default: | |
| 2514 | + XE_WARN_ON("NOT POSSIBLE"); | |
| 2515 | + } | |
| 2516 | +} | |
| 2517 | + | |
| 2518 | +static void trace_xe_vm_ops_execute(struct xe_vma_ops *vops) | |
| 2519 | +{ | |
| 2520 | + struct xe_vma_op *op; | |
| 2521 | + | |
| 2522 | + list_for_each_entry(op, &vops->list, link) | |
| 2523 | + op_trace(op); | |
| 2524 | +} | |
| 2525 | + | |
| 2526 | +static int vm_ops_setup_tile_args(struct xe_vm *vm, struct xe_vma_ops *vops) | |
| 2527 | +{ | |
| 2528 | + struct xe_exec_queue *q = vops->q; | |
| 2529 | + struct xe_tile *tile; | |
| 2530 | + int number_tiles = 0; | |
| 2531 | + u8 id; | |
| 2532 | + | |
| 2533 | + for_each_tile(tile, vm->xe, id) { | |
| 2534 | + if (vops->pt_update_ops[id].num_ops) | |
| 2535 | + ++number_tiles; | |
| 2536 | + | |
| 2537 | + if (vops->pt_update_ops[id].q) | |
| 2538 | + continue; | |
| 2539 | + | |
| 2540 | + if (q) { | |
| 2541 | + vops->pt_update_ops[id].q = q; | |
| 2542 | + if (vm->pt_root[id] && !list_empty(&q->multi_gt_list)) | |
| 2543 | + q = list_next_entry(q, multi_gt_list); | |
| 2544 | + } else { | |
| 2545 | + vops->pt_update_ops[id].q = vm->q[id]; | |
| 2546 | + } | |
| 2547 | + } | |
| 2548 | + | |
| 2549 | + return number_tiles; | |
| 2550 | +} | |
| 2551 | + | |
| 2794 | 2552 | static struct dma_fence *ops_execute(struct xe_vm *vm, |
| 2795 | 2553 | struct xe_vma_ops *vops) |
| 2796 | 2554 | { |
| 2797 | − struct xe_vma_op *op, *next; | |
| 2555 | + struct xe_tile *tile; | |
| 2798 | 2556 | struct dma_fence *fence = NULL; |
| 2557 | + struct dma_fence **fences = NULL; | |
| 2558 | + struct dma_fence_array *cf = NULL; | |
| 2559 | + int number_tiles = 0, current_fence = 0, err; | |
| 2560 | + u8 id; | |
| 2799 | 2561 | |
| 2800 | − list_for_each_entry_safe(op, next, &vops->list, link) { | |
| 2801 | − dma_fence_put(fence); | |
| 2802 | − fence = xe_vma_op_execute(vm, op); | |
| 2803 | − if (IS_ERR(fence)) { | |
| 2804 | − drm_warn(&vm->xe->drm, "VM op(%d) failed with %ld", | |
| 2805 | − op->base.op, PTR_ERR(fence)); | |
| 2806 | − fence = ERR_PTR(-ENOSPC); | |
| 2807 | − break; | |
| 2562 | + number_tiles = vm_ops_setup_tile_args(vm, vops); | |
| 2563 | + if (number_tiles == 0) | |
| 2564 | + return ERR_PTR(-ENODATA); | |
| 2565 | + | |
| 2566 | + if (number_tiles > 1) { | |
| 2567 | + fences = kmalloc_array(number_tiles, sizeof(*fences), | |
| 2568 | + GFP_KERNEL); | |
| 2569 | + if (!fences) { | |
| 2570 | + fence = ERR_PTR(-ENOMEM); | |
| 2571 | + goto err_trace; | |
| 2572 | + } | |
| 2573 | + } | |
| 2574 | + | |
| 2575 | + for_each_tile(tile, vm->xe, id) { | |
| 2576 | + if (!vops->pt_update_ops[id].num_ops) | |
| 2577 | + continue; | |
| 2578 | + | |
| 2579 | + err = xe_pt_update_ops_prepare(tile, vops); | |
| 2580 | + if (err) { | |
| 2581 | + fence = ERR_PTR(err); | |
| 2582 | + goto err_out; | |
| 2808 | 2583 | } |
| 2809 | 2584 | } |
| 2810 | 2585 | |
| 2586 | + trace_xe_vm_ops_execute(vops); | |
| 2587 | + | |
| 2588 | + for_each_tile(tile, vm->xe, id) { | |
| 2589 | + if (!vops->pt_update_ops[id].num_ops) | |
| 2590 | + continue; | |
| 2591 | + | |
| 2592 | + fence = xe_pt_update_ops_run(tile, vops); | |
| 2593 | + if (IS_ERR(fence)) | |
| 2594 | + goto err_out; | |
| 2595 | + | |
| 2596 | + if (fences) | |
| 2597 | + fences[current_fence++] = fence; | |
| 2598 | + } | |
| 2599 | + | |
| 2600 | + if (fences) { | |
| 2601 | + cf = dma_fence_array_create(number_tiles, fences, | |
| 2602 | + vm->composite_fence_ctx, | |
| 2603 | + vm->composite_fence_seqno++, | |
| 2604 | + false); | |
| 2605 | + if (!cf) { | |
| 2606 | + --vm->composite_fence_seqno; | |
| 2607 | + fence = ERR_PTR(-ENOMEM); | |
| 2608 | + goto err_out; | |
| 2609 | + } | |
| 2610 | + fence = &cf->base; | |
| 2611 | + } | |
| 2612 | + | |
| 2613 | + for_each_tile(tile, vm->xe, id) { | |
| 2614 | + if (!vops->pt_update_ops[id].num_ops) | |
| 2615 | + continue; | |
| 2616 | + | |
| 2617 | + xe_pt_update_ops_fini(tile, vops); | |
| 2618 | + } | |
| 2619 | + | |
| 2620 | + return fence; | |
| 2621 | + | |
| 2622 | +err_out: | |
| 2623 | + for_each_tile(tile, vm->xe, id) { | |
| 2624 | + if (!vops->pt_update_ops[id].num_ops) | |
| 2625 | + continue; | |
| 2626 | + | |
| 2627 | + xe_pt_update_ops_abort(tile, vops); | |
| 2628 | + } | |
| 2629 | + while (current_fence) | |
| 2630 | + dma_fence_put(fences[--current_fence]); | |
| 2631 | + kfree(fences); | |
| 2632 | + kfree(cf); | |
| 2633 | + | |
| 2634 | +err_trace: | |
| 2635 | + trace_xe_vm_ops_fail(vm); | |
| 2811 | 2636 | return fence; |
| 2812 | 2637 | } |
| 2813 | 2638 | |
| @@ -2888,12 +2713,10 @@ static int vm_bind_ioctl_ops_execute(struct xe_vm *vm, · 74 unmodified lines | ||
| 2888 | 2713 | fence = ops_execute(vm, vops); |
| 2889 | 2714 | if (IS_ERR(fence)) { |
| 2890 | 2715 | err = PTR_ERR(fence); |
| 2891 | − /* FIXME: Killing VM rather than proper error handling */ | |
| 2892 | − xe_vm_kill(vm, false); | |
| 2893 | 2716 | goto unlock; |
| 2894 | − } else { | |
| 2895 | − vm_bind_ioctl_ops_fini(vm, vops, fence); | |
| 2896 | 2717 | } |
| 2718 | + | |
| 2719 | + vm_bind_ioctl_ops_fini(vm, vops, fence); | |
| 2897 | 2720 | } |
| 2898 | 2721 | |
| 2899 | 2722 | unlock: |
| @@ -2901,11 +2724,18 @@ unlock: · 1 unmodified line | ||
| 2901 | 2724 | return err; |
| 2902 | 2725 | } |
| 2903 | 2726 | |
| 2904 | −#define SUPPORTED_FLAGS \ | |
| 2727 | +#define SUPPORTED_FLAGS_STUB \ | |
| 2905 | 2728 | (DRM_XE_VM_BIND_FLAG_READONLY | \ |
| 2906 | 2729 | DRM_XE_VM_BIND_FLAG_IMMEDIATE | \ |
| 2907 | 2730 | DRM_XE_VM_BIND_FLAG_NULL | \ |
| 2908 | 2731 | DRM_XE_VM_BIND_FLAG_DUMPABLE) |
| 2732 | + | |
| 2733 | +#ifdef TEST_VM_OPS_ERROR | |
| 2734 | +#define SUPPORTED_FLAGS (SUPPORTED_FLAGS_STUB | FORCE_OP_ERROR) | |
| 2735 | +#else | |
| 2736 | +#define SUPPORTED_FLAGS SUPPORTED_FLAGS_STUB | |
| 2737 | +#endif | |
| 2738 | + | |
| 2909 | 2739 | #define XE_64K_PAGE_MASK 0xffffull |
| 2910 | 2740 | #define ALL_DRM_XE_SYNCS_FLAGS (DRM_XE_SYNCS_FLAG_WAIT_FOR_OP) |
| 2911 | 2741 | |
| @@ -2931,7 +2761,7 @@ static int vm_bind_ioctl_check_args(struct xe_device *xe, · 19 unmodified lines | ||
| 2931 | 2761 | sizeof(struct drm_xe_vm_bind_op), |
| 2932 | 2762 | GFP_KERNEL | __GFP_ACCOUNT); |
| 2933 | 2763 | if (!*bind_ops) |
| 2934 | − return -ENOMEM; | |
| 2764 | + return args->num_binds > 1 ? -ENOBUFS : -ENOMEM; | |
| 2935 | 2765 | |
| 2936 | 2766 | err = __copy_from_user(*bind_ops, bind_user, |
| 2937 | 2767 | sizeof(struct drm_xe_vm_bind_op) * |
| @@ -3250,10 +3080,18 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file) · 312 unmodified lines | ||
| 3250 | 3080 | goto unwind_ops; |
| 3251 | 3081 | } |
| 3252 | 3082 | |
| 3253 | − err = vm_bind_ioctl_ops_parse(vm, q, ops[i], syncs, num_syncs, | |
| 3254 | − &vops, i == args->num_binds - 1); | |
| 3083 | + err = vm_bind_ioctl_ops_parse(vm, ops[i], &vops); | |
| 3255 | 3084 | if (err) |
| 3256 | 3085 | goto unwind_ops; |
| 3086 | + | |
| 3087 | +#ifdef TEST_VM_OPS_ERROR | |
| 3088 | + if (flags & FORCE_OP_ERROR) { | |
| 3089 | + vops.inject_error = true; | |
| 3090 | + vm->xe->vm_inject_error_position = | |
| 3091 | + (vm->xe->vm_inject_error_position + 1) % | |
| 3092 | + FORCE_OP_ERROR_COUNT; | |
| 3093 | + } | |
| 3094 | +#endif | |
| 3257 | 3095 | } |
| 3258 | 3096 | |
| 3259 | 3097 | /* Nothing to do */ |
| @@ -3262,11 +3100,16 @@ int xe_vm_bind_ioctl(struct drm_device *dev, void *data, struct drm_file *file) · 2 unmodified lines | ||
| 3262 | 3100 | goto unwind_ops; |
| 3263 | 3101 | } |
| 3264 | 3102 | |
| 3103 | + err = xe_vma_ops_alloc(&vops, args->num_binds > 1); | |
| 3104 | + if (err) | |
| 3105 | + goto unwind_ops; | |
| 3106 | + | |
| 3265 | 3107 | err = vm_bind_ioctl_ops_execute(vm, &vops); |
| 3266 | 3108 | |
| 3267 | 3109 | unwind_ops: |
| 3268 | 3110 | if (err && err != -ENODATA) |
| 3269 | 3111 | vm_bind_ioctl_ops_unwind(vm, ops, args->num_binds); |
| 3112 | + xe_vma_ops_fini(&vops); | |
| 3270 | 3113 | for (i = args->num_binds - 1; i >= 0; --i) |
| 3271 | 3114 | if (ops[i]) |
| 3272 | 3115 | drm_gpuva_ops_free(&vm->gpuvm, ops[i]); |
| @@ -3337,10 +3180,10 @@ int xe_vm_invalidate_vma(struct xe_vma *vma) · 64 unmodified lines | ||
| 3337 | 3180 | { |
| 3338 | 3181 | struct xe_device *xe = xe_vma_vm(vma)->xe; |
| 3339 | 3182 | struct xe_tile *tile; |
| 3183 | + struct xe_gt_tlb_invalidation_fence fence[XE_MAX_TILES_PER_DEVICE]; | |
| 3340 | 3184 | u32 tile_needs_invalidate = 0; |
| 3341 | − int seqno[XE_MAX_TILES_PER_DEVICE]; | |
| 3342 | 3185 | u8 id; |
| 3343 | − int ret; | |
| 3186 | + int ret = 0; | |
| 3344 | 3187 | |
| 3345 | 3188 | xe_assert(xe, !xe_vma_is_null(vma)); |
| 3346 | 3189 | trace_xe_vma_invalidate(vma); |
| @@ -3365,29 +3208,33 @@ int xe_vm_invalidate_vma(struct xe_vma *vma) · 18 unmodified lines | ||
| 3365 | 3208 | |
| 3366 | 3209 | for_each_tile(tile, xe, id) { |
| 3367 | 3210 | if (xe_pt_zap_ptes(tile, vma)) { |
| 3368 | − tile_needs_invalidate |= BIT(id); | |
| 3369 | 3211 | xe_device_wmb(xe); |
| 3212 | + xe_gt_tlb_invalidation_fence_init(tile->primary_gt, | |
| 3213 | + &fence[id], true); | |
| 3214 | + | |
| 3370 | 3215 | /* |
| 3371 | 3216 | * FIXME: We potentially need to invalidate multiple |
| 3372 | 3217 | * GTs within the tile |
| 3373 | 3218 | */ |
| 3374 | − seqno[id] = xe_gt_tlb_invalidation_vma(tile->primary_gt, NULL, vma); | |
| 3375 | − if (seqno[id] < 0) | |
| 3376 | − return seqno[id]; | |
| 3377 | − } | |
| 3378 | − } | |
| 3219 | + ret = xe_gt_tlb_invalidation_vma(tile->primary_gt, | |
| 3220 | + &fence[id], vma); | |
| 3221 | + if (ret < 0) { | |
| 3222 | + xe_gt_tlb_invalidation_fence_fini(&fence[id]); | |
| 3223 | + goto wait; | |
| 3224 | + } | |
| 3379 | 3225 | |
| 3380 | − for_each_tile(tile, xe, id) { | |
| 3381 | − if (tile_needs_invalidate & BIT(id)) { | |
| 3382 | − ret = xe_gt_tlb_invalidation_wait(tile->primary_gt, seqno[id]); | |
| 3383 | − if (ret < 0) | |
| 3384 | − return ret; | |
| 3226 | + tile_needs_invalidate |= BIT(id); | |
| 3385 | 3227 | } |
| 3386 | 3228 | } |
| 3387 | 3229 | |
| 3230 | +wait: | |
| 3231 | + for_each_tile(tile, xe, id) | |
| 3232 | + if (tile_needs_invalidate & BIT(id)) | |
| 3233 | + xe_gt_tlb_invalidation_fence_wait(&fence[id]); | |
| 3234 | + | |
| 3388 | 3235 | vma->tile_invalidated = vma->tile_mask; |
| 3389 | 3236 | |
| 3390 | − return 0; | |
| 3237 | + return ret; | |
| 3391 | 3238 | } |
| 3392 | 3239 | |
| 3393 | 3240 | struct xe_vm_snapshot { |
| @@ -259,6 +259,8 @@ static inline struct dma_resv *xe_vm_resv(struct xe_vm *vm) · 258 unmodified lines | ||
| 259 | 259 | return drm_gpuvm_resv(&vm->gpuvm); |
| 260 | 260 | } |
| 261 | 261 | |
| 262 | +void xe_vm_kill(struct xe_vm *vm, bool unlocked); | |
| 263 | + | |
| 262 | 264 | /** |
| 263 | 265 | * xe_vm_assert_held(vm) - Assert that the vm's reservation object is held. |
| 264 | 266 | * @vm: The vm |
| @@ -21,18 +21,27 @@ struct xe_bo; · 20 unmodified lines | ||
| 21 | 21 | struct xe_sync_entry; |
| 22 | 22 | struct xe_user_fence; |
| 23 | 23 | struct xe_vm; |
| 24 | +struct xe_vm_pgtable_update_op; | |
| 25 | + | |
| 26 | +#if IS_ENABLED(CONFIG_DRM_XE_DEBUG) | |
| 27 | +#define TEST_VM_OPS_ERROR | |
| 28 | +#define FORCE_OP_ERROR BIT(31) | |
| 29 | + | |
| 30 | +#define FORCE_OP_ERROR_LOCK 0 | |
| 31 | +#define FORCE_OP_ERROR_PREPARE 1 | |
| 32 | +#define FORCE_OP_ERROR_RUN 2 | |
| 33 | +#define FORCE_OP_ERROR_COUNT 3 | |
| 34 | +#endif | |
| 24 | 35 | |
| 25 | 36 | #define XE_VMA_READ_ONLY DRM_GPUVA_USERBITS |
| 26 | 37 | #define XE_VMA_DESTROYED (DRM_GPUVA_USERBITS << 1) |
| 27 | 38 | #define XE_VMA_ATOMIC_PTE_BIT (DRM_GPUVA_USERBITS << 2) |
| 28 | −#define XE_VMA_FIRST_REBIND (DRM_GPUVA_USERBITS << 3) | |
| 29 | −#define XE_VMA_LAST_REBIND (DRM_GPUVA_USERBITS << 4) | |
| 30 | −#define XE_VMA_PTE_4K (DRM_GPUVA_USERBITS << 5) | |
| 31 | −#define XE_VMA_PTE_2M (DRM_GPUVA_USERBITS << 6) | |
| 32 | −#define XE_VMA_PTE_1G (DRM_GPUVA_USERBITS << 7) | |
| 33 | −#define XE_VMA_PTE_64K (DRM_GPUVA_USERBITS << 8) | |
| 34 | −#define XE_VMA_PTE_COMPACT (DRM_GPUVA_USERBITS << 9) | |
| 35 | −#define XE_VMA_DUMPABLE (DRM_GPUVA_USERBITS << 10) | |
| 39 | +#define XE_VMA_PTE_4K (DRM_GPUVA_USERBITS << 3) | |
| 40 | +#define XE_VMA_PTE_2M (DRM_GPUVA_USERBITS << 4) | |
| 41 | +#define XE_VMA_PTE_1G (DRM_GPUVA_USERBITS << 5) | |
| 42 | +#define XE_VMA_PTE_64K (DRM_GPUVA_USERBITS << 6) | |
| 43 | +#define XE_VMA_PTE_COMPACT (DRM_GPUVA_USERBITS << 7) | |
| 44 | +#define XE_VMA_DUMPABLE (DRM_GPUVA_USERBITS << 8) | |
| 36 | 45 | |
| 37 | 46 | /** struct xe_userptr - User pointer */ |
| 38 | 47 | struct xe_userptr { |
| @@ -99,6 +108,9 @@ struct xe_vma { · 60 unmodified lines | ||
| 99 | 108 | */ |
| 100 | 109 | u8 tile_present; |
| 101 | 110 | |
| 111 | + /** @tile_staged: bind is staged for this VMA */ | |
| 112 | + u8 tile_staged; | |
| 113 | + | |
| 102 | 114 | /** |
| 103 | 115 | * @pat_index: The pat index to use when encoding the PTEs for this vma. |
| 104 | 116 | */ |
| @@ -314,31 +326,18 @@ struct xe_vma_op_prefetch { · 209 unmodified lines | ||
| 314 | 326 | |
| 315 | 327 | /** enum xe_vma_op_flags - flags for VMA operation */ |
| 316 | 328 | enum xe_vma_op_flags { |
| 317 | − /** @XE_VMA_OP_FIRST: first VMA operation for a set of syncs */ | |
| 318 | − XE_VMA_OP_FIRST = BIT(0), | |
| 319 | − /** @XE_VMA_OP_LAST: last VMA operation for a set of syncs */ | |
| 320 | − XE_VMA_OP_LAST = BIT(1), | |
| 321 | 329 | /** @XE_VMA_OP_COMMITTED: VMA operation committed */ |
| 322 | − XE_VMA_OP_COMMITTED = BIT(2), | |
| 330 | + XE_VMA_OP_COMMITTED = BIT(0), | |
| 323 | 331 | /** @XE_VMA_OP_PREV_COMMITTED: Previous VMA operation committed */ |
| 324 | − XE_VMA_OP_PREV_COMMITTED = BIT(3), | |
| 332 | + XE_VMA_OP_PREV_COMMITTED = BIT(1), | |
| 325 | 333 | /** @XE_VMA_OP_NEXT_COMMITTED: Next VMA operation committed */ |
| 326 | − XE_VMA_OP_NEXT_COMMITTED = BIT(4), | |
| 334 | + XE_VMA_OP_NEXT_COMMITTED = BIT(2), | |
| 327 | 335 | }; |
| 328 | 336 | |
| 329 | 337 | /** struct xe_vma_op - VMA operation */ |
| 330 | 338 | struct xe_vma_op { |
| 331 | 339 | /** @base: GPUVA base operation */ |
| 332 | 340 | struct drm_gpuva_op base; |
| 333 | − /** @q: exec queue for this operation */ | |
| 334 | − struct xe_exec_queue *q; | |
| 335 | − /** | |
| 336 | − * @syncs: syncs for this operation, only used on first and last | |
| 337 | − * operation | |
| 338 | − */ | |
| 339 | − struct xe_sync_entry *syncs; | |
| 340 | − /** @num_syncs: number of syncs */ | |
| 341 | − u32 num_syncs; | |
| 342 | 341 | /** @link: async operation link */ |
| 343 | 342 | struct list_head link; |
| 344 | 343 | /** @flags: operation flags */ |
| @@ -362,12 +361,18 @@ struct xe_vma_ops { · 17 unmodified lines | ||
| 362 | 361 | struct list_head list; |
| 363 | 362 | /** @vm: VM */ |
| 364 | 363 | struct xe_vm *vm; |
| 365 | − /** @q: exec queue these operations */ | |
| 364 | + /** @q: exec queue for VMA operations */ | |
| 366 | 365 | struct xe_exec_queue *q; |
| 367 | 366 | /** @syncs: syncs these operation */ |
| 368 | 367 | struct xe_sync_entry *syncs; |
| 369 | 368 | /** @num_syncs: number of syncs */ |
| 370 | 369 | u32 num_syncs; |
| 370 | + /** @pt_update_ops: page table update operations */ | |
| 371 | + struct xe_vm_pgtable_update_ops pt_update_ops[XE_MAX_TILES_PER_DEVICE]; | |
| 372 | +#ifdef TEST_VM_OPS_ERROR | |
| 373 | + /** @inject_error: inject error to test error handling */ | |
| 374 | + bool inject_error; | |
| 375 | +#endif | |
| 371 | 376 | }; |
| 372 | 377 | |
| 373 | 378 | #endif |
| @@ -486,6 +486,10 @@ static const struct xe_rtp_entry_sr engine_was[] = { · 485 unmodified lines | ||
| 486 | 486 | XE_RTP_RULES(GRAPHICS_VERSION(2004), FUNC(xe_rtp_match_first_render_or_compute)), |
| 487 | 487 | XE_RTP_ACTIONS(SET(TDL_TSL_CHICKEN, SLM_WMTP_RESTORE)) |
| 488 | 488 | }, |
| 489 | + { XE_RTP_NAME("14021402888"), | |
| 490 | + XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), | |
| 491 | + XE_RTP_ACTIONS(SET(HALF_SLICE_CHICKEN7, CLEAR_OPTIMIZATION_DISABLE)) | |
| 492 | + }, | |
| 489 | 493 | |
| 490 | 494 | /* Xe2_HPG */ |
| 491 | 495 | |
| @@ -539,6 +543,16 @@ static const struct xe_rtp_entry_sr engine_was[] = { · 47 unmodified lines | ||
| 539 | 543 | XE_RTP_ACTIONS(SET(HALF_SLICE_CHICKEN7, CLEAR_OPTIMIZATION_DISABLE)) |
| 540 | 544 | }, |
| 541 | 545 | |
| 546 | + /* Xe2_LPM */ | |
| 547 | + | |
| 548 | + { XE_RTP_NAME("16021639441"), | |
| 549 | + XE_RTP_RULES(MEDIA_VERSION(2000)), | |
| 550 | + XE_RTP_ACTIONS(SET(CSFE_CHICKEN1(0), | |
| 551 | + GHWSP_CSB_REPORT_DIS | | |
| 552 | + PPHWSP_CSB_AND_TIMESTAMP_REPORT_DIS, | |
| 553 | + XE_RTP_ACTION_FLAG(ENGINE_BASE))) | |
| 554 | + }, | |
| 555 | + | |
| 542 | 556 | /* Xe2_HPM */ |
| 543 | 557 | |
| 544 | 558 | { XE_RTP_NAME("16021639441"), |
| @@ -741,6 +755,7 @@ void xe_wa_process_oob(struct xe_gt *gt) · 196 unmodified lines | ||
| 741 | 755 | |
| 742 | 756 | xe_rtp_process_ctx_enable_active_tracking(&ctx, gt->wa_active.oob, |
| 743 | 757 | ARRAY_SIZE(oob_was)); |
| 758 | + gt->wa_active.oob_initialized = true; | |
| 744 | 759 | xe_rtp_process(&ctx, oob_was); |
| 745 | 760 | } |
| 746 | 761 | |
| @@ -6,6 +6,8 @@ · 5 unmodified lines | ||
| 6 | 6 | #ifndef _XE_WA_ |
| 7 | 7 | #define _XE_WA_ |
| 8 | 8 | |
| 9 | +#include "xe_assert.h" | |
| 10 | + | |
| 9 | 11 | struct drm_printer; |
| 10 | 12 | struct xe_gt; |
| 11 | 13 | struct xe_hw_engine; |
| @@ -25,6 +27,9 @@ void xe_wa_dump(struct xe_gt *gt, struct drm_printer *p); · 13 unmodified lines | ||
| 25 | 27 | * @gt__: gt instance |
| 26 | 28 | * @id__: XE_OOB_<id__>, as generated by build system in generated/xe_wa_oob.h |
| 27 | 29 | */ |
| 28 | −#define XE_WA(gt__, id__) test_bit(XE_WA_OOB_ ## id__, (gt__)->wa_active.oob) | |
| 30 | +#define XE_WA(gt__, id__) ({ \ | |
| 31 | + xe_gt_assert(gt__, (gt__)->wa_active.oob_initialized); \ | |
| 32 | + test_bit(XE_WA_OOB_ ## id__, (gt__)->wa_active.oob); \ | |
| 33 | +}) | |
| 29 | 34 | |
| 30 | 35 | #endif |
| @@ -29,3 +29,5 @@ · 28 unmodified lines | ||
| 29 | 29 | 13011645652 GRAPHICS_VERSION(2004) |
| 30 | 30 | 22019338487 MEDIA_VERSION(2000) |
| 31 | 31 | GRAPHICS_VERSION(2001) |
| 32 | +22019338487_display PLATFORM(LUNARLAKE) | |
| 33 | +16023588340 GRAPHICS_VERSION(2001) | |
| @@ -517,7 +517,14 @@ struct drm_xe_query_gt_list { · 516 unmodified lines | ||
| 517 | 517 | * available per Dual Sub Slices (DSS). For example a query response |
| 518 | 518 | * containing the following in mask: |
| 519 | 519 | * ``EU_PER_DSS ff ff 00 00 00 00 00 00`` |
| 520 | − * means each DSS has 16 EU. | |
| 520 | + * means each DSS has 16 SIMD8 EUs. This type may be omitted if device | |
| 521 | + * doesn't have SIMD8 EUs. | |
| 522 | + * - %DRM_XE_TOPO_SIMD16_EU_PER_DSS - To query the mask of SIMD16 Execution | |
| 523 | + * Units (EU) available per Dual Sub Slices (DSS). For example a query | |
| 524 | + * response containing the following in mask: | |
| 525 | + * ``SIMD16_EU_PER_DSS ff ff 00 00 00 00 00 00`` | |
| 526 | + * means each DSS has 16 SIMD16 EUs. This type may be omitted if device | |
| 527 | + * doesn't have SIMD16 EUs. | |
| 521 | 528 | */ |
| 522 | 529 | struct drm_xe_query_topology_mask { |
| 523 | 530 | /** @gt_id: GT ID the mask is associated with */ |
| @@ -527,6 +534,7 @@ struct drm_xe_query_topology_mask { · 3 unmodified lines | ||
| 527 | 534 | #define DRM_XE_TOPO_DSS_COMPUTE 2 |
| 528 | 535 | #define DRM_XE_TOPO_L3_BANK 3 |
| 529 | 536 | #define DRM_XE_TOPO_EU_PER_DSS 4 |
| 537 | +#define DRM_XE_TOPO_SIMD16_EU_PER_DSS 5 | |
| 530 | 538 | /** @type: type of mask */ |
| 531 | 539 | __u16 type; |
| 532 | 540 | |
| @@ -1590,10 +1598,10 @@ enum drm_xe_oa_property_id { · 1057 unmodified lines | ||
| 1590 | 1598 | * b. Counter select c. Counter size and d. BC report. Also refer to the |
| 1591 | 1599 | * oa_formats array in drivers/gpu/drm/xe/xe_oa.c. |
| 1592 | 1600 | */ |
| 1593 | −#define DRM_XE_OA_FORMAT_MASK_FMT_TYPE (0xff << 0) | |
| 1594 | −#define DRM_XE_OA_FORMAT_MASK_COUNTER_SEL (0xff << 8) | |
| 1595 | −#define DRM_XE_OA_FORMAT_MASK_COUNTER_SIZE (0xff << 16) | |
| 1596 | −#define DRM_XE_OA_FORMAT_MASK_BC_REPORT (0xff << 24) | |
| 1601 | +#define DRM_XE_OA_FORMAT_MASK_FMT_TYPE (0xffu << 0) | |
| 1602 | +#define DRM_XE_OA_FORMAT_MASK_COUNTER_SEL (0xffu << 8) | |
| 1603 | +#define DRM_XE_OA_FORMAT_MASK_COUNTER_SIZE (0xffu << 16) | |
| 1604 | +#define DRM_XE_OA_FORMAT_MASK_BC_REPORT (0xffu << 24) | |
| 1597 | 1605 | |
| 1598 | 1606 | /** |
| 1599 | 1607 | * @DRM_XE_OA_PROPERTY_OA_PERIOD_EXPONENT: Requests periodic OA unit |