Resguardo inicial

This commit is contained in:
lastdragon
2026-09-06 12:53:21 -06:00
parent 662efe3c2a
commit ad2088d178
94853 changed files with 43200404 additions and 0 deletions
@@ -0,0 +1,4 @@
# SPDX-License-Identifier: GPL-2.0-only
*.hdrtest
/generated
/xe_gen_wa_oob
@@ -0,0 +1,18 @@
# xe dependencies
CONFIG_KUNIT=y
CONFIG_PCI=y
CONFIG_PCI_IOV=y
CONFIG_DEBUG_FS=y
CONFIG_DRM=y
CONFIG_DRM_FBDEV_EMULATION=y
CONFIG_DRM_KMS_HELPER=y
CONFIG_DRM_XE=y
CONFIG_DRM_XE_DISPLAY=n
CONFIG_EXPERT=y
CONFIG_FB=y
CONFIG_DRM_XE_KUNIT_TEST=y
CONFIG_LOCK_DEBUGGING_SUPPORT=y
CONFIG_PROVE_LOCKING=y
CONFIG_DEBUG_MUTEXES=y
CONFIG_LOCKDEP=y
CONFIG_DEBUG_LOCKDEP=y
+142
View File
@@ -0,0 +1,142 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_XE
tristate "Intel Xe2 Graphics"
depends on DRM && PCI
depends on KUNIT || !KUNIT
depends on INTEL_VSEC || !INTEL_VSEC
depends on X86_PLATFORM_DEVICES || !(X86 && ACPI)
depends on PAGE_SIZE_4KB || COMPILE_TEST || BROKEN
select INTERVAL_TREE
# we need shmfs for the swappable backing store, and in particular
# the shmem_readpage() which depends upon tmpfs
select SHMEM
select TMPFS
select DRM_BUDDY
select DRM_CLIENT_SELECTION
select DRM_KMS_HELPER
select DRM_KUNIT_TEST_HELPERS if DRM_XE_KUNIT_TEST != n
select DRM_PANEL
select DRM_SUBALLOC_HELPER
select DRM_DISPLAY_DP_HELPER
select DRM_DISPLAY_DSC_HELPER
select DRM_DISPLAY_HDCP_HELPER
select DRM_DISPLAY_HDMI_HELPER
select DRM_DISPLAY_HELPER
select DRM_MIPI_DSI
select RELAY
select IRQ_WORK
# xe depends on ACPI_VIDEO when ACPI is enabled
# but for select to work, need to select ACPI_VIDEO's dependencies, ick
select BACKLIGHT_CLASS_DEVICE if ACPI
select INPUT if ACPI
select ACPI_VIDEO if X86 && ACPI
select ACPI_WMI if X86 && ACPI
select SYNC_FILE
select CRC32
select SND_HDA_I915 if SND_HDA_CORE
select CEC_CORE if CEC_NOTIFIER
select VMAP_PFN
select DRM_TTM
select DRM_TTM_HELPER
select DRM_EXEC
select DRM_GPUSVM if !UML
select DRM_GPUVM
select DRM_SCHED
select MMU_NOTIFIER
select WANT_DEV_COREDUMP
select AUXILIARY_BUS
select REGMAP if I2C
help
Driver for Intel Xe2 series GPUs and later. Experimental support
for Xe series is also available.
If "M" is selected, the module will be called xe.
config DRM_XE_DISPLAY
bool "Enable display support"
depends on DRM_XE && DRM_XE=m && HAS_IOPORT
select FB_IOMEM_HELPERS if DRM_FBDEV_EMULATION
select I2C
select I2C_ALGOBIT
default y
help
Disable this option only if you want to compile out display support.
config DRM_XE_DP_TUNNEL
bool "Enable DP tunnel support"
depends on DRM_XE_DISPLAY
depends on USB4
select DRM_DISPLAY_DP_TUNNEL
default y
help
Choose this option to detect DP tunnels and enable the Bandwidth
Allocation mode for such tunnels. This allows using the maximum
resolution allowed by the link BW on all displays sharing the
link BW, for instance on a Thunderbolt link.
If in doubt say "Y".
config DRM_XE_GPUSVM
bool "Enable CPU to GPU address mirroring"
depends on DRM_XE
depends on !UML
depends on ZONE_DEVICE
default y
select DEVICE_PRIVATE
select DRM_GPUSVM
help
Enable this option if you want support for CPU to GPU address
mirroring.
If in doubt say "Y".
config DRM_XE_PAGEMAP
bool "Enable device memory pool for SVM"
depends on DRM_XE_GPUSVM
select GET_FREE_REGION
default y
help
Disable this option only if you don't want to expose local device
memory for SVM. Will reduce KMD memory footprint when disabled.
If in doubt say "Y".
config DRM_XE_FORCE_PROBE
string "Force probe xe for selected Intel hardware IDs"
depends on DRM_XE
help
This is the default value for the xe.force_probe module
parameter. Using the module parameter overrides this option.
Force probe the xe for Intel graphics devices that are
recognized but not properly supported by this kernel version. It is
recommended to upgrade to a kernel version with proper support as soon
as it is available.
It can also be used to block the probe of recognized and fully
supported devices.
Use "" to disable force probe. If in doubt, use this.
Use "<pci-id>[,<pci-id>,...]" to force probe the xe for listed
devices. For example, "4500" or "4500,4571".
Use "*" to force probe the driver for all known devices.
Use "!" right before the ID to block the probe of the device. For
example, "4500,!4571" forces the probe of 4500 and blocks the probe of
4571.
Use "!*" to block the probe of the driver for all known devices.
menu "drm/Xe Debugging"
depends on DRM_XE
depends on EXPERT
source "drivers/gpu/drm/xe/Kconfig.debug"
endmenu
menu "drm/xe Profile Guided Optimisation"
visible if EXPERT
depends on DRM_XE
source "drivers/gpu/drm/xe/Kconfig.profile"
endmenu
@@ -0,0 +1,114 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_XE_WERROR
bool "Force GCC to throw an error instead of a warning when compiling"
# As this may inadvertently break the build, only allow the user
# to shoot oneself in the foot iff they aim really hard
depends on EXPERT
# We use the dependency on !COMPILE_TEST to not be enabled in
# allmodconfig or allyesconfig configurations
depends on !COMPILE_TEST
default n
help
Add -Werror to the build flags for (and only for) xe.ko.
Do not enable this unless you are writing code for the xe.ko module.
Recommended for driver developers only.
If in doubt, say "N".
config DRM_XE_DEBUG
bool "Enable additional driver debugging"
depends on DRM_XE
depends on EXPERT
depends on !COMPILE_TEST
default n
help
Choose this option to turn on extra driver debugging that may affect
performance but will catch some internal issues.
Recommended for driver developers only.
If in doubt, say "N".
config DRM_XE_DEBUG_VM
bool "Enable extra VM debugging info"
default n
help
Enable extra VM debugging info
Recommended for driver developers only.
If in doubt, say "N".
config DRM_XE_DEBUG_SRIOV
bool "Enable extra SR-IOV debugging"
default n
imply DRM_XE_DEBUG_MEMIRQ
help
Enable extra SR-IOV debugging info.
Recommended for driver developers only.
If in doubt, say "N".
config DRM_XE_DEBUG_MEMIRQ
bool "Enable extra memirq debugging"
default n
help
Choose this option to enable additional debugging info for
memory based interrupts.
Recommended for driver developers only.
If in doubt, say "N".
config DRM_XE_DEBUG_MEM
bool "Enable passing SYS/VRAM addresses to user space"
default n
help
Pass object location through uapi. Intended for extended
testing and development only.
Recommended for driver developers only.
If in doubt, say "N".
config DRM_XE_KUNIT_TEST
tristate "KUnit tests for the drm xe driver" if !KUNIT_ALL_TESTS
depends on DRM_XE && KUNIT && DEBUG_FS
default KUNIT_ALL_TESTS
select DRM_EXPORT_FOR_TESTS if m
help
Choose this option to allow the driver to perform selftests under
the kunit framework
Recommended for driver developers only.
If in doubt, say "N".
config DRM_XE_DEBUG_GUC
bool "Enable extra GuC related debug options"
depends on DRM_XE_DEBUG
default n
select STACKDEPOT
help
Choose this option when debugging guc issues.
The GuC log buffer is increased to the maximum allowed, which should
be large enough for complex issues. The tracking of FAST_REQ messages
is extended to include a record of the calling stack, which is then
dumped on a FAST_REQ error notification.
Recommended for driver developers only.
If in doubt, say "N".
config DRM_XE_USERPTR_INVAL_INJECT
bool "Inject userptr invalidation -EINVAL errors"
depends on DRM_GPUSVM
default n
help
Choose this option when debugging error paths that
are hit during checks for userptr invalidations.
Recommended for driver developers only.
If in doubt, say "N".
@@ -0,0 +1,55 @@
# SPDX-License-Identifier: GPL-2.0-only
config DRM_XE_JOB_TIMEOUT_MAX
int "Default max job timeout (ms)"
default 10000 # milliseconds
help
Configures the default max job timeout after which job will
be forcefully taken away from scheduler.
config DRM_XE_JOB_TIMEOUT_MIN
int "Default min job timeout (ms)"
default 1 # milliseconds
help
Configures the default min job timeout after which job will
be forcefully taken away from scheduler.
config DRM_XE_TIMESLICE_MAX
int "Default max timeslice duration (us)"
default 10000000 # microseconds
help
Configures the default max timeslice duration between multiple
contexts by guc scheduling.
config DRM_XE_TIMESLICE_MIN
int "Default min timeslice duration (us)"
default 1 # microseconds
help
Configures the default min timeslice duration between multiple
contexts by guc scheduling.
config DRM_XE_PREEMPT_TIMEOUT
int "Preempt timeout (us, jiffy granularity)"
default 640000 # microseconds
help
How long to wait (in microseconds) for a preemption event to occur
when submitting a new context. If the current context does not hit
an arbitration point and yield to HW before the timer expires, the
HW will be reset to allow the more important context to execute.
config DRM_XE_PREEMPT_TIMEOUT_MAX
int "Default max preempt timeout (us)"
default 10000000 # microseconds
help
Configures the default max preempt timeout after which context
will be forcefully taken away and higher priority context will
run.
config DRM_XE_PREEMPT_TIMEOUT_MIN
int "Default min preempt timeout (us)"
default 1 # microseconds
help
Configures the default min preempt timeout after which context
will be forcefully taken away and higher priority context will
run.
config DRM_XE_ENABLE_SCHEDTIMEOUT_LIMIT
bool "Default configuration of limitation on scheduler timeout"
default y
help
Configures the enablement of limitation on scheduler timeout
to apply to applicable user. For elevated user, all above MIN
and MAX values will apply when this configuration is enable to
apply limitation. By default limitation is applied.
+393
View File
@@ -0,0 +1,393 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for the drm device driver. This driver provides support for the
# Direct Rendering Infrastructure (DRI) in XFree86 4.1.0 and higher.
# Enable W=1 warnings not enabled in drm subsystem Makefile
subdir-ccflags-y += $(call cc-option, -Wformat-truncation)
# Enable -Werror in CI and development
subdir-ccflags-$(CONFIG_DRM_XE_WERROR) += -Werror
subdir-ccflags-y += -I$(obj) -I$(src)
# generated sources
hostprogs := xe_gen_wa_oob
generated_oob := $(obj)/generated/xe_wa_oob.c $(obj)/generated/xe_wa_oob.h
quiet_cmd_wa_oob = GEN $(notdir $(generated_oob))
cmd_wa_oob = mkdir -p $(@D); $(obj)/xe_gen_wa_oob $(src)/xe_wa_oob.rules $(generated_oob)
$(obj)/generated/%_wa_oob.c $(obj)/generated/%_wa_oob.h: $(obj)/xe_gen_wa_oob \
$(src)/xe_wa_oob.rules
$(call cmd,wa_oob)
generated_device_oob := $(obj)/generated/xe_device_wa_oob.c $(obj)/generated/xe_device_wa_oob.h
quiet_cmd_device_wa_oob = GEN $(notdir $(generated_device_oob))
cmd_device_wa_oob = mkdir -p $(@D); $(obj)/xe_gen_wa_oob $(src)/xe_device_wa_oob.rules $(generated_device_oob)
$(obj)/generated/%_device_wa_oob.c $(obj)/generated/%_device_wa_oob.h: $(obj)/xe_gen_wa_oob \
$(src)/xe_device_wa_oob.rules
$(call cmd,device_wa_oob)
# Please keep these build lists sorted!
# core driver code
xe-y += xe_bb.o \
xe_bo.o \
xe_bo_evict.o \
xe_dep_scheduler.o \
xe_devcoredump.o \
xe_device.o \
xe_device_sysfs.o \
xe_dma_buf.o \
xe_drm_client.o \
xe_drm_ras.o \
xe_eu_stall.o \
xe_exec.o \
xe_exec_queue.o \
xe_execlist.o \
xe_force_wake.o \
xe_ggtt.o \
xe_gpu_scheduler.o \
xe_gsc.o \
xe_gsc_debugfs.o \
xe_gsc_proxy.o \
xe_gsc_submit.o \
xe_gt.o \
xe_gt_ccs_mode.o \
xe_gt_clock.o \
xe_gt_freq.o \
xe_gt_idle.o \
xe_gt_mcr.o \
xe_gt_sysfs.o \
xe_gt_throttle.o \
xe_gt_topology.o \
xe_guc.o \
xe_guc_ads.o \
xe_guc_buf.o \
xe_guc_capture.o \
xe_guc_ct.o \
xe_guc_db_mgr.o \
xe_guc_engine_activity.o \
xe_guc_hwconfig.o \
xe_guc_id_mgr.o \
xe_guc_klv_helpers.o \
xe_guc_log.o \
xe_guc_pagefault.o \
xe_guc_pc.o \
xe_guc_rc.o \
xe_guc_submit.o \
xe_guc_tlb_inval.o \
xe_heci_gsc.o \
xe_huc.o \
xe_hw_engine.o \
xe_hw_engine_class_sysfs.o \
xe_hw_engine_group.o \
xe_hw_error.o \
xe_hw_fence.o \
xe_irq.o \
xe_late_bind_fw.o \
xe_lrc.o \
xe_mem_pool.o \
xe_migrate.o \
xe_mmio.o \
xe_mmio_gem.o \
xe_mocs.o \
xe_module.o \
xe_nvm.o \
xe_oa.o \
xe_observation.o \
xe_pagefault.o \
xe_page_reclaim.o \
xe_pat.o \
xe_pci.o \
xe_pci_rebar.o \
xe_pcode.o \
xe_pm.o \
xe_preempt_fence.o \
xe_psmi.o \
xe_pt.o \
xe_pt_walk.o \
xe_pxp.o \
xe_pxp_debugfs.o \
xe_pxp_submit.o \
xe_query.o \
xe_range_fence.o \
xe_ras.o \
xe_reg_sr.o \
xe_reg_whitelist.o \
xe_ring_ops.o \
xe_rtp.o \
xe_sa.o \
xe_sched_job.o \
xe_shrinker.o \
xe_soc_remapper.o \
xe_step.o \
xe_survivability_mode.o \
xe_sync.o \
xe_sysctrl.o \
xe_sysctrl_event.o \
xe_sysctrl_mailbox.o \
xe_tile.o \
xe_tile_sysfs.o \
xe_tlb_inval.o \
xe_tlb_inval_job.o \
xe_trace.o \
xe_trace_bo.o \
xe_trace_guc.o \
xe_trace_lrc.o \
xe_ttm_stolen_mgr.o \
xe_ttm_sys_mgr.o \
xe_ttm_vram_mgr.o \
xe_tuning.o \
xe_uc.o \
xe_uc_fw.o \
xe_validation.o \
xe_vm.o \
xe_vm_madvise.o \
xe_vram.o \
xe_vram_freq.o \
xe_vsec.o \
xe_wa.o \
xe_wait_user_fence.o \
xe_wopcm.o
xe-$(CONFIG_I2C) += xe_i2c.o
xe-$(CONFIG_DRM_XE_GPUSVM) += xe_svm.o
xe-$(CONFIG_DRM_GPUSVM) += xe_userptr.o
# graphics hardware monitoring (HWMON) support
xe-$(CONFIG_HWMON) += xe_hwmon.o
xe-$(CONFIG_PERF_EVENTS) += xe_pmu.o
xe-$(CONFIG_CONFIGFS_FS) += xe_configfs.o
# graphics virtualization (SR-IOV) support
xe-y += \
xe_gt_sriov_vf.o \
xe_guc_relay.o \
xe_memirq.o \
xe_sriov.o \
xe_sriov_vf.o \
xe_sriov_vf_ccs.o \
xe_tile_sriov_vf.o
xe-$(CONFIG_PCI_IOV) += \
xe_gt_sriov_pf.o \
xe_gt_sriov_pf_config.o \
xe_gt_sriov_pf_control.o \
xe_gt_sriov_pf_migration.o \
xe_gt_sriov_pf_monitor.o \
xe_gt_sriov_pf_policy.o \
xe_gt_sriov_pf_service.o \
xe_lmtt.o \
xe_lmtt_2l.o \
xe_lmtt_ml.o \
xe_mert.o \
xe_pci_sriov.o \
xe_sriov_packet.o \
xe_sriov_pf.o \
xe_sriov_pf_control.o \
xe_sriov_pf_debugfs.o \
xe_sriov_pf_migration.o \
xe_sriov_pf_provision.o \
xe_sriov_pf_service.o \
xe_sriov_pf_sysfs.o \
xe_tile_sriov_pf_debugfs.o
ifdef CONFIG_XE_VFIO_PCI
xe-$(CONFIG_PCI_IOV) += xe_sriov_vfio.o
endif
# include helpers for tests even when XE is built-in
ifdef CONFIG_DRM_XE_KUNIT_TEST
xe-y += tests/xe_kunit_helpers.o
endif
# i915 Display compat #defines and #includes
subdir-ccflags-$(CONFIG_DRM_XE_DISPLAY) += \
-I$(src)/compat-i915-headers \
-I$(srctree)/drivers/gpu/drm/i915/display/
# Rule to build display code shared with i915
$(obj)/i915-display/%.o: $(srctree)/drivers/gpu/drm/i915/display/%.c FORCE
$(call cmd,force_checksrc)
$(call if_changed_rule,cc_o_c)
# Display code specific to xe
xe-$(CONFIG_DRM_XE_DISPLAY) += \
display/xe_display.o \
display/xe_display_bo.o \
display/xe_display_pcode.o \
display/xe_display_rpm.o \
display/xe_display_wa.o \
display/xe_dsb_buffer.o \
display/xe_fb_pin.o \
display/xe_frontbuffer.o \
display/xe_hdcp_gsc.o \
display/xe_initial_plane.o \
display/xe_panic.o \
display/xe_stolen.o \
display/xe_tdf.o
# Display code shared with i915
xe-$(CONFIG_DRM_XE_DISPLAY) += \
i915-display/icl_dsi.o \
i915-display/intel_alpm.o \
i915-display/intel_atomic.o \
i915-display/intel_audio.o \
i915-display/intel_backlight.o \
i915-display/intel_bios.o \
i915-display/intel_bo.o \
i915-display/intel_bw.o \
i915-display/intel_casf.o \
i915-display/intel_cdclk.o \
i915-display/intel_cmtg.o \
i915-display/intel_color.o \
i915-display/intel_colorop.o \
i915-display/intel_color_pipeline.o \
i915-display/intel_combo_phy.o \
i915-display/intel_connector.o \
i915-display/intel_crtc.o \
i915-display/intel_crtc_state_dump.o \
i915-display/intel_cursor.o \
i915-display/intel_cx0_phy.o \
i915-display/intel_dbuf_bw.o \
i915-display/intel_ddi.o \
i915-display/intel_ddi_buf_trans.o \
i915-display/intel_de.o \
i915-display/intel_display.o \
i915-display/intel_display_conversion.o \
i915-display/intel_display_device.o \
i915-display/intel_display_driver.o \
i915-display/intel_display_irq.o \
i915-display/intel_display_params.o \
i915-display/intel_display_power.o \
i915-display/intel_display_power_map.o \
i915-display/intel_display_power_well.o \
i915-display/intel_display_reset.o \
i915-display/intel_display_rpm.o \
i915-display/intel_display_rps.o \
i915-display/intel_display_trace.o \
i915-display/intel_display_utils.o \
i915-display/intel_display_wa.o \
i915-display/intel_dkl_phy.o \
i915-display/intel_dmc.o \
i915-display/intel_dmc_wl.o \
i915-display/intel_dp.o \
i915-display/intel_dp_aux.o \
i915-display/intel_dp_aux_backlight.o \
i915-display/intel_dp_hdcp.o \
i915-display/intel_dp_link_training.o \
i915-display/intel_dp_mst.o \
i915-display/intel_dp_test.o \
i915-display/intel_dpll.o \
i915-display/intel_dpll_mgr.o \
i915-display/intel_dpt.o \
i915-display/intel_dram.o \
i915-display/intel_drrs.o \
i915-display/intel_dsb.o \
i915-display/intel_dsi.o \
i915-display/intel_dsi_dcs_backlight.o \
i915-display/intel_dsi_vbt.o \
i915-display/intel_encoder.o \
i915-display/intel_fb.o \
i915-display/intel_fbc.o \
i915-display/intel_fdi.o \
i915-display/intel_fifo_underrun.o \
i915-display/intel_flipq.o \
i915-display/intel_frontbuffer.o \
i915-display/intel_global_state.o \
i915-display/intel_gmbus.o \
i915-display/intel_hdcp.o \
i915-display/intel_hdcp_gsc_message.o \
i915-display/intel_hdmi.o \
i915-display/intel_hotplug.o \
i915-display/intel_hotplug_irq.o \
i915-display/intel_hti.o \
i915-display/intel_initial_plane.o \
i915-display/intel_link_bw.o \
i915-display/intel_lspcon.o \
i915-display/intel_lt_phy.o \
i915-display/intel_mchbar.o \
i915-display/intel_modeset_lock.o \
i915-display/intel_modeset_setup.o \
i915-display/intel_modeset_verify.o \
i915-display/intel_overlay.o \
i915-display/intel_panel.o \
i915-display/intel_parent.o \
i915-display/intel_pch.o \
i915-display/intel_pfit.o \
i915-display/intel_plane.o \
i915-display/intel_pmdemand.o \
i915-display/intel_pps.o \
i915-display/intel_psr.o \
i915-display/intel_qp_tables.o \
i915-display/intel_quirks.o \
i915-display/intel_rom.o \
i915-display/intel_snps_hdmi_pll.o \
i915-display/intel_snps_phy.o \
i915-display/intel_tc.o \
i915-display/intel_vblank.o \
i915-display/intel_vdsc.o \
i915-display/intel_vga.o \
i915-display/intel_vrr.o \
i915-display/intel_wm.o \
i915-display/skl_prefill.o \
i915-display/skl_scaler.o \
i915-display/skl_universal_plane.o \
i915-display/skl_watermark.o \
i915-display/vlv_sideband.o
ifeq ($(CONFIG_ACPI),y)
xe-$(CONFIG_DRM_XE_DISPLAY) += \
i915-display/intel_acpi.o \
i915-display/intel_opregion.o
endif
ifeq ($(CONFIG_DRM_FBDEV_EMULATION),y)
xe-$(CONFIG_DRM_XE_DISPLAY) += i915-display/intel_fbdev.o
endif
ifeq ($(CONFIG_DEBUG_FS),y)
xe-y += xe_debugfs.o \
xe_gt_debugfs.o \
xe_gt_sriov_vf_debugfs.o \
xe_gt_stats.o \
xe_guc_debugfs.o \
xe_huc_debugfs.o \
xe_tile_debugfs.o \
xe_uc_debugfs.o
xe-$(CONFIG_PCI_IOV) += xe_gt_sriov_pf_debugfs.o
xe-$(CONFIG_DRM_XE_DISPLAY) += \
i915-display/intel_display_debugfs.o \
i915-display/intel_display_debugfs_params.o \
i915-display/intel_pipe_crc.o
endif
xe-$(CONFIG_DRM_XE_DP_TUNNEL) += \
i915-display/intel_dp_tunnel.o
obj-$(CONFIG_DRM_XE) += xe.o
obj-$(CONFIG_DRM_XE_KUNIT_TEST) += tests/
# header test
hdrtest_find_args := -not -path xe_rtp_helpers.h
ifneq ($(CONFIG_DRM_XE_DISPLAY),y)
hdrtest_find_args += -not -path display/\* -not -path compat-i915-headers/\* -not -path xe_display.h
endif
always-$(CONFIG_DRM_XE_WERROR) += \
$(patsubst %.h,%.hdrtest, $(shell cd $(src) && find * -name '*.h' $(hdrtest_find_args)))
quiet_cmd_hdrtest = HDRTEST $(patsubst %.hdrtest,%.h,$@)
cmd_hdrtest = $(CC) $(filter-out $(CFLAGS_GCOV), $(c_flags)) -S -o /dev/null -x c /dev/null -include $< -include $<; \
$(srctree)/scripts/kernel-doc -none -Werror $<; touch $@
$(obj)/%.hdrtest: $(src)/%.h FORCE
$(call if_changed_dep,hdrtest)
uses_generated_oob := $(addprefix $(obj)/, $(xe-y))
$(uses_generated_oob): $(obj)/generated/xe_wa_oob.h $(obj)/generated/xe_device_wa_oob.h
@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _ABI_GSC_COMMAND_HEADER_ABI_H
#define _ABI_GSC_COMMAND_HEADER_ABI_H
#include <linux/types.h>
struct intel_gsc_mtl_header {
u32 validity_marker;
#define GSC_HECI_VALIDITY_MARKER 0xA578875A
u8 heci_client_id;
u8 reserved1;
u16 header_version;
#define MTL_GSC_HEADER_VERSION 1
/* FW allows host to decide host_session handle as it sees fit. */
u64 host_session_handle;
/* handle generated by FW for messages that need to be re-submitted */
u64 gsc_message_handle;
u32 message_size; /* lower 20 bits only, upper 12 are reserved */
/*
* Flags mask:
* Bit 0: Pending
* Bit 1: Session Cleanup;
* Bits 2-15: Flags
* Bits 16-31: Extension Size
* According to internal spec flags are either input or output
* we distinguish the flags using OUTFLAG or INFLAG
*/
u32 flags;
#define GSC_OUTFLAG_MSG_PENDING BIT(0)
#define GSC_INFLAG_MSG_CLEANUP BIT(1)
u32 status;
} __packed;
#endif
@@ -0,0 +1,39 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _ABI_GSC_MKHI_COMMANDS_ABI_H
#define _ABI_GSC_MKHI_COMMANDS_ABI_H
#include <linux/types.h>
/* Heci client ID for MKHI commands */
#define HECI_MEADDRESS_MKHI 7
/* Generic MKHI header */
struct gsc_mkhi_header {
u8 group_id;
u8 command;
u8 reserved;
u8 result;
} __packed;
/* GFX_SRV commands */
#define MKHI_GROUP_ID_GFX_SRV 0x30
#define MKHI_GFX_SRV_GET_HOST_COMPATIBILITY_VERSION (0x42)
struct gsc_get_compatibility_version_in {
struct gsc_mkhi_header header;
} __packed;
struct gsc_get_compatibility_version_out {
struct gsc_mkhi_header header;
u16 proj_major;
u16 compat_major;
u16 compat_minor;
u16 reserved[5];
} __packed;
#endif
@@ -0,0 +1,44 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _ABI_GSC_PROXY_COMMANDS_ABI_H
#define _ABI_GSC_PROXY_COMMANDS_ABI_H
#include <linux/types.h>
/* Heci client ID for proxy commands */
#define HECI_MEADDRESS_PROXY 10
/* FW-defined proxy header */
struct xe_gsc_proxy_header {
/*
* hdr:
* Bits 0-7: type of the proxy message (see enum xe_gsc_proxy_type)
* Bits 8-15: rsvd
* Bits 16-31: length in bytes of the payload following the proxy header
*/
u32 hdr;
#define GSC_PROXY_TYPE GENMASK(7, 0)
#define GSC_PROXY_PAYLOAD_LENGTH GENMASK(31, 16)
u32 source; /* Source of the Proxy message */
u32 destination; /* Destination of the Proxy message */
#define GSC_PROXY_ADDRESSING_KMD 0x10000
#define GSC_PROXY_ADDRESSING_GSC 0x20000
#define GSC_PROXY_ADDRESSING_CSME 0x30000
u32 status; /* Command status */
} __packed;
/* FW-defined proxy types */
enum xe_gsc_proxy_type {
GSC_PROXY_MSG_TYPE_PROXY_INVALID = 0,
GSC_PROXY_MSG_TYPE_PROXY_QUERY = 1,
GSC_PROXY_MSG_TYPE_PROXY_PAYLOAD = 2,
GSC_PROXY_MSG_TYPE_PROXY_END = 3,
GSC_PROXY_MSG_TYPE_PROXY_NOTIFICATION = 4,
};
#endif
@@ -0,0 +1,100 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _ABI_GSC_PXP_COMMANDS_ABI_H
#define _ABI_GSC_PXP_COMMANDS_ABI_H
#include <linux/sizes.h>
#include <linux/types.h>
/* Heci client ID for PXP commands */
#define HECI_MEADDRESS_PXP 17
#define PXP_APIVER(x, y) (((x) & 0xFFFF) << 16 | ((y) & 0xFFFF))
/*
* A PXP sub-section in an HECI packet can be up to 64K big in each direction.
* This does not include the top-level GSC header.
*/
#define PXP_MAX_PACKET_SIZE SZ_64K
/*
* there are a lot of status codes for PXP, but we only define the cross-API
* common ones that we actually can handle in the kernel driver. Other failure
* codes should be printed to error msg for debug.
*/
enum pxp_status {
PXP_STATUS_SUCCESS = 0x0,
PXP_STATUS_ERROR_API_VERSION = 0x1002,
PXP_STATUS_NOT_READY = 0x100e,
PXP_STATUS_PLATFCONFIG_KF1_NOVERIF = 0x101a,
PXP_STATUS_PLATFCONFIG_KF1_BAD = 0x101f,
PXP_STATUS_PLATFCONFIG_FIXED_KF1_NOT_SUPPORTED = 0x1037,
PXP_STATUS_OP_NOT_PERMITTED = 0x4013
};
/* Common PXP FW message header */
struct pxp_cmd_header {
u32 api_version;
u32 command_id;
union {
u32 status; /* out */
u32 stream_id; /* in */
#define PXP_CMDHDR_EXTDATA_SESSION_VALID GENMASK(0, 0)
#define PXP_CMDHDR_EXTDATA_APP_TYPE GENMASK(1, 1)
#define PXP_CMDHDR_EXTDATA_SESSION_ID GENMASK(17, 2)
};
/* Length of the message (excluding the header) */
u32 buffer_len;
} __packed;
#define PXP43_CMDID_INVALIDATE_STREAM_KEY 0x00000007
#define PXP43_CMDID_INIT_SESSION 0x00000036
#define PXP43_CMDID_NEW_HUC_AUTH 0x0000003F /* MTL+ */
/* PXP-Input-Packet: HUC Auth-only */
struct pxp43_new_huc_auth_in {
struct pxp_cmd_header header;
u64 huc_base_address;
u32 huc_size;
} __packed;
/* PXP-Output-Packet: HUC Load and Authentication or Auth-only */
struct pxp43_huc_auth_out {
struct pxp_cmd_header header;
} __packed;
/* PXP-Input-Packet: Init PXP session */
struct pxp43_create_arb_in {
struct pxp_cmd_header header;
/* header.stream_id fields for vesion 4.3 of Init PXP session: */
#define PXP43_INIT_SESSION_VALID BIT(0)
#define PXP43_INIT_SESSION_APPTYPE BIT(1)
#define PXP43_INIT_SESSION_APPID GENMASK(17, 2)
u32 protection_mode;
#define PXP43_INIT_SESSION_PROTECTION_ARB 0x2
u32 sub_session_id;
u32 init_flags;
u32 rsvd[12];
} __packed;
/* PXP-Input-Packet: Init PXP session */
struct pxp43_create_arb_out {
struct pxp_cmd_header header;
u32 rsvd[8];
} __packed;
/* PXP-Input-Packet: Invalidate Stream Key */
struct pxp43_inv_stream_key_in {
struct pxp_cmd_header header;
u32 rsvd[3];
} __packed;
/* PXP-Output-Packet: Invalidate Stream Key */
struct pxp43_inv_stream_key_out {
struct pxp_cmd_header header;
u32 rsvd;
} __packed;
#endif
@@ -0,0 +1,287 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2014-2021 Intel Corporation
*/
#ifndef _ABI_GUC_ACTIONS_ABI_H
#define _ABI_GUC_ACTIONS_ABI_H
/**
* DOC: HOST2GUC_SELF_CFG
*
* This message is used by Host KMD to setup of the `GuC Self Config KLVs`_.
*
* This message must be sent as `MMIO HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_HOST2GUC_SELF_CFG` = 0x0508 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:16 | **KLV_KEY** - KLV key, see `GuC Self Config KLVs`_ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | **KLV_LEN** - KLV length |
* | | | |
* | | | - 32 bit KLV = 1 |
* | | | - 64 bit KLV = 2 |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | **VALUE32** - Bits 31-0 of the KLV value |
* +---+-------+--------------------------------------------------------------+
* | 3 | 31:0 | **VALUE64** - Bits 63-32 of the KLV value (**KLV_LEN** = 2) |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = **NUM** - 1 if KLV was parsed, 0 if not recognized |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_HOST2GUC_SELF_CFG 0x0508
#define HOST2GUC_SELF_CFG_REQUEST_MSG_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 3u)
#define HOST2GUC_SELF_CFG_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define HOST2GUC_SELF_CFG_REQUEST_MSG_1_KLV_KEY (0xffffu << 16)
#define HOST2GUC_SELF_CFG_REQUEST_MSG_1_KLV_LEN (0xffffu << 0)
#define HOST2GUC_SELF_CFG_REQUEST_MSG_2_VALUE32 GUC_HXG_REQUEST_MSG_n_DATAn
#define HOST2GUC_SELF_CFG_REQUEST_MSG_3_VALUE64 GUC_HXG_REQUEST_MSG_n_DATAn
#define HOST2GUC_SELF_CFG_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN
#define HOST2GUC_SELF_CFG_RESPONSE_MSG_0_NUM GUC_HXG_RESPONSE_MSG_0_DATA0
/**
* DOC: HOST2GUC_CONTROL_CTB
*
* This H2G action allows Vf Host to enable or disable H2G and G2H `CT Buffer`_.
*
* This message must be sent as `MMIO HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_HOST2GUC_CONTROL_CTB` = 0x4509 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **CONTROL** - control `CTB based communication`_ |
* | | | |
* | | | - _`GUC_CTB_CONTROL_DISABLE` = 0 |
* | | | - _`GUC_CTB_CONTROL_ENABLE` = 1 |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = MBZ |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_HOST2GUC_CONTROL_CTB 0x4509
#define HOST2GUC_CONTROL_CTB_REQUEST_MSG_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 1u)
#define HOST2GUC_CONTROL_CTB_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define HOST2GUC_CONTROL_CTB_REQUEST_MSG_1_CONTROL GUC_HXG_REQUEST_MSG_n_DATAn
#define GUC_CTB_CONTROL_DISABLE 0u
#define GUC_CTB_CONTROL_ENABLE 1u
#define HOST2GUC_CONTROL_CTB_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN
#define HOST2GUC_CONTROL_CTB_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0
/* legacy definitions */
enum xe_guc_action {
XE_GUC_ACTION_DEFAULT = 0x0,
XE_GUC_ACTION_REQUEST_PREEMPTION = 0x2,
XE_GUC_ACTION_REQUEST_ENGINE_RESET = 0x3,
XE_GUC_ACTION_ALLOCATE_DOORBELL = 0x10,
XE_GUC_ACTION_DEALLOCATE_DOORBELL = 0x20,
XE_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE = 0x30,
XE_GUC_ACTION_UK_LOG_ENABLE_LOGGING = 0x40,
XE_GUC_ACTION_FORCE_LOG_BUFFER_FLUSH = 0x302,
XE_GUC_ACTION_ENTER_S_STATE = 0x501,
XE_GUC_ACTION_EXIT_S_STATE = 0x502,
XE_GUC_ACTION_GLOBAL_SCHED_POLICY_CHANGE = 0x506,
XE_GUC_ACTION_UPDATE_SCHEDULING_POLICIES_KLV = 0x509,
XE_GUC_ACTION_SCHED_CONTEXT = 0x1000,
XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET = 0x1001,
XE_GUC_ACTION_SCHED_CONTEXT_MODE_DONE = 0x1002,
XE_GUC_ACTION_SCHED_ENGINE_MODE_SET = 0x1003,
XE_GUC_ACTION_SCHED_ENGINE_MODE_DONE = 0x1004,
XE_GUC_ACTION_SET_CONTEXT_PRIORITY = 0x1005,
XE_GUC_ACTION_SET_CONTEXT_EXECUTION_QUANTUM = 0x1006,
XE_GUC_ACTION_SET_CONTEXT_PREEMPTION_TIMEOUT = 0x1007,
XE_GUC_ACTION_CONTEXT_RESET_NOTIFICATION = 0x1008,
XE_GUC_ACTION_ENGINE_FAILURE_NOTIFICATION = 0x1009,
XE_GUC_ACTION_HOST2GUC_UPDATE_CONTEXT_POLICIES = 0x100B,
XE_GUC_ACTION_AUTHENTICATE_HUC = 0x4000,
XE_GUC_ACTION_GET_HWCONFIG = 0x4100,
XE_GUC_ACTION_REGISTER_CONTEXT = 0x4502,
XE_GUC_ACTION_DEREGISTER_CONTEXT = 0x4503,
XE_GUC_ACTION_REGISTER_COMMAND_TRANSPORT_BUFFER = 0x4505,
XE_GUC_ACTION_DEREGISTER_COMMAND_TRANSPORT_BUFFER = 0x4506,
XE_GUC_ACTION_REGISTER_G2G = 0x4507,
XE_GUC_ACTION_DEREGISTER_G2G = 0x4508,
XE_GUC_ACTION_DEREGISTER_CONTEXT_DONE = 0x4600,
XE_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC = 0x4601,
XE_GUC_ACTION_REGISTER_CONTEXT_MULTI_QUEUE = 0x4602,
XE_GUC_ACTION_MULTI_QUEUE_CONTEXT_CGP_SYNC = 0x4603,
XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CONTEXT_CGP_SYNC_DONE = 0x4604,
XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CGP_CONTEXT_ERROR = 0x4605,
XE_GUC_ACTION_CLIENT_SOFT_RESET = 0x5507,
XE_GUC_ACTION_SET_ENG_UTIL_BUFF = 0x550A,
XE_GUC_ACTION_SET_DEVICE_ENGINE_ACTIVITY_BUFFER = 0x550C,
XE_GUC_ACTION_SET_FUNCTION_ENGINE_ACTIVITY_BUFFER = 0x550D,
XE_GUC_ACTION_OPT_IN_FEATURE_KLV = 0x550E,
XE_GUC_ACTION_NOTIFY_MEMORY_CAT_ERROR = 0x6000,
XE_GUC_ACTION_REPORT_PAGE_FAULT_REQ_DESC = 0x6002,
XE_GUC_ACTION_PAGE_FAULT_RES_DESC = 0x6003,
XE_GUC_ACTION_ACCESS_COUNTER_NOTIFY = 0x6004,
XE_GUC_ACTION_TLB_INVALIDATION = 0x7000,
XE_GUC_ACTION_TLB_INVALIDATION_DONE = 0x7001,
XE_GUC_ACTION_TLB_INVALIDATION_ALL = 0x7002,
XE_GUC_ACTION_PAGE_RECLAMATION = 0x7003,
XE_GUC_ACTION_PAGE_RECLAMATION_DONE = 0x7004,
XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION = 0x8002,
XE_GUC_ACTION_NOTIFY_FLUSH_LOG_BUFFER_TO_FILE = 0x8003,
XE_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED = 0x8004,
XE_GUC_ACTION_NOTIFY_EXCEPTION = 0x8005,
XE_GUC_ACTION_TEST_G2G_SEND = 0xF001,
XE_GUC_ACTION_TEST_G2G_RECV = 0xF002,
XE_GUC_ACTION_LIMIT
};
enum xe_guc_preempt_options {
XE_GUC_PREEMPT_OPTION_DROP_WORK_Q = 0x4,
XE_GUC_PREEMPT_OPTION_DROP_SUBMIT_Q = 0x8,
};
enum xe_guc_register_context_param_offsets {
XE_GUC_REGISTER_CONTEXT_DATA_0_MBZ = 0,
XE_GUC_REGISTER_CONTEXT_DATA_1_FLAGS,
XE_GUC_REGISTER_CONTEXT_DATA_2_CONTEXT_INDEX,
XE_GUC_REGISTER_CONTEXT_DATA_3_ENGINE_CLASS,
XE_GUC_REGISTER_CONTEXT_DATA_4_ENGINE_SUBMIT_MASK,
XE_GUC_REGISTER_CONTEXT_DATA_5_WQ_DESC_ADDR_LOWER,
XE_GUC_REGISTER_CONTEXT_DATA_6_WQ_DESC_ADDR_UPPER,
XE_GUC_REGISTER_CONTEXT_DATA_7_WQ_BUF_BASE_LOWER,
XE_GUC_REGISTER_CONTEXT_DATA_8_WQ_BUF_BASE_UPPER,
XE_GUC_REGISTER_CONTEXT_DATA_9_WQ_BUF_SIZE,
XE_GUC_REGISTER_CONTEXT_DATA_10_HW_LRC_ADDR,
XE_GUC_REGISTER_CONTEXT_MSG_LEN,
};
enum xe_guc_register_context_multi_lrc_param_offsets {
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_0_MBZ = 0,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_1_FLAGS,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_2_PARENT_CONTEXT,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_3_ENGINE_CLASS,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_4_ENGINE_SUBMIT_MASK,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_5_WQ_DESC_ADDR_LOWER,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_6_WQ_DESC_ADDR_UPPER,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_7_WQ_BUF_BASE_LOWER,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_8_WQ_BUF_BASE_UPPER,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_9_WQ_BUF_SIZE,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_10_NUM_CTXS,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_DATA_11_HW_LRC_ADDR,
XE_GUC_REGISTER_CONTEXT_MULTI_LRC_MSG_MIN_LEN = 11,
};
enum xe_guc_report_status {
XE_GUC_REPORT_STATUS_UNKNOWN = 0x0,
XE_GUC_REPORT_STATUS_ACKED = 0x1,
XE_GUC_REPORT_STATUS_ERROR = 0x2,
XE_GUC_REPORT_STATUS_COMPLETE = 0x4,
};
enum xe_guc_sleep_state_status {
XE_GUC_SLEEP_STATE_SUCCESS = 0x1,
XE_GUC_SLEEP_STATE_PREEMPT_TO_IDLE_FAILED = 0x2,
XE_GUC_SLEEP_STATE_ENGINE_RESET_FAILED = 0x3
#define XE_GUC_SLEEP_STATE_INVALID_MASK 0x80000000
};
#define GUC_LOG_CONTROL_LOGGING_ENABLED (1 << 0)
#define GUC_LOG_CONTROL_VERBOSITY_SHIFT 4
#define GUC_LOG_CONTROL_VERBOSITY_MASK (0xF << GUC_LOG_CONTROL_VERBOSITY_SHIFT)
#define GUC_LOG_CONTROL_DEFAULT_LOGGING (1 << 8)
enum xe_guc_state_capture_event_status {
XE_GUC_STATE_CAPTURE_EVENT_STATUS_SUCCESS = 0x0,
XE_GUC_STATE_CAPTURE_EVENT_STATUS_NOSPACE = 0x1,
};
#define XE_GUC_STATE_CAPTURE_EVENT_STATUS_MASK 0x000000FF
#define XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION_DATA_LEN 1
#define XE_GUC_TLB_INVAL_TYPE_SHIFT 0
#define XE_GUC_TLB_INVAL_MODE_SHIFT 8
/* Flush PPC or SMRO caches along with TLB invalidation request */
#define XE_GUC_TLB_INVAL_FLUSH_CACHE (1 << 31)
enum xe_guc_tlb_invalidation_type {
XE_GUC_TLB_INVAL_FULL = 0x0,
XE_GUC_TLB_INVAL_PAGE_SELECTIVE = 0x1,
XE_GUC_TLB_INVAL_PAGE_SELECTIVE_CTX = 0x2,
XE_GUC_TLB_INVAL_GUC = 0x3,
};
/*
* 0: Heavy mode of Invalidation:
* The pipeline of the engine(s) for which the invalidation is targeted to is
* blocked, and all the in-flight transactions are guaranteed to be Globally
* Observed before completing the TLB invalidation
* 1: Lite mode of Invalidation:
* TLBs of the targeted engine(s) are immediately invalidated.
* In-flight transactions are NOT guaranteed to be Globally Observed before
* completing TLB invalidation.
* Light Invalidation Mode is to be used only when
* it can be guaranteed (by SW) that the address translations remain invariant
* for the in-flight transactions across the TLB invalidation. In other words,
* this mode can be used when the TLB invalidation is intended to clear out the
* stale cached translations that are no longer in use. Light Invalidation Mode
* is much faster than the Heavy Invalidation Mode, as it does not wait for the
* in-flight transactions to be GOd.
*/
enum xe_guc_tlb_inval_mode {
XE_GUC_TLB_INVAL_MODE_HEAVY = 0x0,
XE_GUC_TLB_INVAL_MODE_LITE = 0x1,
};
/*
* GuC to GuC communication (de-)registration fields:
*/
enum xe_guc_g2g_type {
XE_G2G_TYPE_IN = 0x0,
XE_G2G_TYPE_OUT,
XE_G2G_TYPE_LIMIT,
};
#define XE_G2G_REGISTER_DEVICE REG_GENMASK(16, 16)
#define XE_G2G_REGISTER_TILE REG_GENMASK(15, 12)
#define XE_G2G_REGISTER_TYPE REG_GENMASK(11, 8)
#define XE_G2G_REGISTER_SIZE REG_GENMASK(7, 0)
#define XE_G2G_DEREGISTER_DEVICE REG_GENMASK(16, 16)
#define XE_G2G_DEREGISTER_TILE REG_GENMASK(15, 12)
#define XE_G2G_DEREGISTER_TYPE REG_GENMASK(11, 8)
/* invalid type for XE_GUC_ACTION_NOTIFY_MEMORY_CAT_ERROR */
#define XE_GUC_CAT_ERR_TYPE_INVALID 0xdeadbeef
#endif
@@ -0,0 +1,279 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2021 Intel Corporation
*/
#ifndef _GUC_ACTIONS_SLPC_ABI_H_
#define _GUC_ACTIONS_SLPC_ABI_H_
#include <linux/types.h>
/**
* DOC: SLPC SHARED DATA STRUCTURE
*
* +----+------+--------------------------------------------------------------+
* | CL | Bytes| Description |
* +====+======+==============================================================+
* | 1 | 0-3 | SHARED DATA SIZE |
* | +------+--------------------------------------------------------------+
* | | 4-7 | GLOBAL STATE |
* | +------+--------------------------------------------------------------+
* | | 8-11 | DISPLAY DATA ADDRESS |
* | +------+--------------------------------------------------------------+
* | | 12:63| PADDING |
* +----+------+--------------------------------------------------------------+
* | | 0:63 | PADDING(PLATFORM INFO) |
* +----+------+--------------------------------------------------------------+
* | 3 | 0-3 | TASK STATE DATA |
* + +------+--------------------------------------------------------------+
* | | 4:63 | PADDING |
* +----+------+--------------------------------------------------------------+
* |4-21|0:1087| OVERRIDE PARAMS AND BIT FIELDS |
* +----+------+--------------------------------------------------------------+
* | | | PADDING + EXTRA RESERVED PAGE |
* +----+------+--------------------------------------------------------------+
*/
/*
* SLPC exposes certain parameters for global configuration by the host.
* These are referred to as override parameters, because in most cases
* the host will not need to modify the default values used by SLPC.
* SLPC remembers the default values which allows the host to easily restore
* them by simply unsetting the override. The host can set or unset override
* parameters during SLPC (re-)initialization using the SLPC Reset event.
* The host can also set or unset override parameters on the fly using the
* Parameter Set and Parameter Unset events
*/
#define SLPC_MAX_OVERRIDE_PARAMETERS 256
#define SLPC_OVERRIDE_BITFIELD_SIZE \
(SLPC_MAX_OVERRIDE_PARAMETERS / 32)
#define SLPC_PAGE_SIZE_BYTES 4096
#define SLPC_CACHELINE_SIZE_BYTES 64
#define SLPC_SHARED_DATA_SIZE_BYTE_HEADER SLPC_CACHELINE_SIZE_BYTES
#define SLPC_SHARED_DATA_SIZE_BYTE_PLATFORM_INFO SLPC_CACHELINE_SIZE_BYTES
#define SLPC_SHARED_DATA_SIZE_BYTE_TASK_STATE SLPC_CACHELINE_SIZE_BYTES
#define SLPC_SHARED_DATA_MODE_DEFN_TABLE_SIZE SLPC_PAGE_SIZE_BYTES
#define SLPC_SHARED_DATA_SIZE_BYTE_MAX (2 * SLPC_PAGE_SIZE_BYTES)
/*
* Cacheline size aligned (Total size needed for
* SLPM_KMD_MAX_OVERRIDE_PARAMETERS=256 is 1088 bytes)
*/
#define SLPC_OVERRIDE_PARAMS_TOTAL_BYTES (((((SLPC_MAX_OVERRIDE_PARAMETERS * 4) \
+ ((SLPC_MAX_OVERRIDE_PARAMETERS / 32) * 4)) \
+ (SLPC_CACHELINE_SIZE_BYTES - 1)) / SLPC_CACHELINE_SIZE_BYTES) * \
SLPC_CACHELINE_SIZE_BYTES)
#define SLPC_SHARED_DATA_SIZE_BYTE_OTHER (SLPC_SHARED_DATA_SIZE_BYTE_MAX - \
(SLPC_SHARED_DATA_SIZE_BYTE_HEADER \
+ SLPC_SHARED_DATA_SIZE_BYTE_PLATFORM_INFO \
+ SLPC_SHARED_DATA_SIZE_BYTE_TASK_STATE \
+ SLPC_OVERRIDE_PARAMS_TOTAL_BYTES \
+ SLPC_SHARED_DATA_MODE_DEFN_TABLE_SIZE))
enum slpc_task_enable {
SLPC_PARAM_TASK_DEFAULT = 0,
SLPC_PARAM_TASK_ENABLED,
SLPC_PARAM_TASK_DISABLED,
SLPC_PARAM_TASK_UNKNOWN
};
enum slpc_global_state {
SLPC_GLOBAL_STATE_NOT_RUNNING = 0,
SLPC_GLOBAL_STATE_INITIALIZING = 1,
SLPC_GLOBAL_STATE_RESETTING = 2,
SLPC_GLOBAL_STATE_RUNNING = 3,
SLPC_GLOBAL_STATE_SHUTTING_DOWN = 4,
SLPC_GLOBAL_STATE_ERROR = 5
};
enum slpc_param_id {
SLPC_PARAM_TASK_ENABLE_GTPERF = 0,
SLPC_PARAM_TASK_DISABLE_GTPERF = 1,
SLPC_PARAM_TASK_ENABLE_BALANCER = 2,
SLPC_PARAM_TASK_DISABLE_BALANCER = 3,
SLPC_PARAM_TASK_ENABLE_DCC = 4,
SLPC_PARAM_TASK_DISABLE_DCC = 5,
SLPC_PARAM_GLOBAL_MIN_GT_UNSLICE_FREQ_MHZ = 6,
SLPC_PARAM_GLOBAL_MAX_GT_UNSLICE_FREQ_MHZ = 7,
SLPC_PARAM_GLOBAL_MIN_GT_SLICE_FREQ_MHZ = 8,
SLPC_PARAM_GLOBAL_MAX_GT_SLICE_FREQ_MHZ = 9,
SLPC_PARAM_GTPERF_THRESHOLD_MAX_FPS = 10,
SLPC_PARAM_GLOBAL_DISABLE_GT_FREQ_MANAGEMENT = 11,
SLPC_PARAM_GTPERF_ENABLE_FRAMERATE_STALLING = 12,
SLPC_PARAM_GLOBAL_DISABLE_RC6_MODE_CHANGE = 13,
SLPC_PARAM_GLOBAL_OC_UNSLICE_FREQ_MHZ = 14,
SLPC_PARAM_GLOBAL_OC_SLICE_FREQ_MHZ = 15,
SLPC_PARAM_GLOBAL_ENABLE_IA_GT_BALANCING = 16,
SLPC_PARAM_GLOBAL_ENABLE_ADAPTIVE_BURST_TURBO = 17,
SLPC_PARAM_GLOBAL_ENABLE_EVAL_MODE = 18,
SLPC_PARAM_GLOBAL_ENABLE_BALANCER_IN_NON_GAMING_MODE = 19,
SLPC_PARAM_GLOBAL_RT_MODE_TURBO_FREQ_DELTA_MHZ = 20,
SLPC_PARAM_PWRGATE_RC_MODE = 21,
SLPC_PARAM_EDR_MODE_COMPUTE_TIMEOUT_MS = 22,
SLPC_PARAM_EDR_QOS_FREQ_MHZ = 23,
SLPC_PARAM_MEDIA_FF_RATIO_MODE = 24,
SLPC_PARAM_ENABLE_IA_FREQ_LIMITING = 25,
SLPC_PARAM_STRATEGIES = 26,
SLPC_PARAM_POWER_PROFILE = 27,
SLPC_PARAM_IGNORE_EFFICIENT_FREQUENCY = 28,
SLPC_MAX_PARAM = 32,
};
enum slpc_media_ratio_mode {
SLPC_MEDIA_RATIO_MODE_DYNAMIC_CONTROL = 0,
SLPC_MEDIA_RATIO_MODE_FIXED_ONE_TO_ONE = 1,
SLPC_MEDIA_RATIO_MODE_FIXED_ONE_TO_TWO = 2,
};
enum slpc_gucrc_mode {
SLPC_GUCRC_MODE_HW = 0,
SLPC_GUCRC_MODE_GUCRC_NO_RC6 = 1,
SLPC_GUCRC_MODE_GUCRC_STATIC_TIMEOUT = 2,
SLPC_GUCRC_MODE_GUCRC_DYNAMIC_HYSTERESIS = 3,
SLPC_GUCRC_MODE_MAX,
};
enum slpc_event_id {
SLPC_EVENT_RESET = 0,
SLPC_EVENT_SHUTDOWN = 1,
SLPC_EVENT_PLATFORM_INFO_CHANGE = 2,
SLPC_EVENT_DISPLAY_MODE_CHANGE = 3,
SLPC_EVENT_FLIP_COMPLETE = 4,
SLPC_EVENT_QUERY_TASK_STATE = 5,
SLPC_EVENT_PARAMETER_SET = 6,
SLPC_EVENT_PARAMETER_UNSET = 7,
};
struct slpc_task_state_data {
union {
u32 task_status_padding;
struct {
u32 status;
#define SLPC_GTPERF_TASK_ENABLED REG_BIT(0)
#define SLPC_DCC_TASK_ENABLED REG_BIT(11)
#define SLPC_IN_DCC REG_BIT(12)
#define SLPC_BALANCER_ENABLED REG_BIT(15)
#define SLPC_IBC_TASK_ENABLED REG_BIT(16)
#define SLPC_BALANCER_IA_LMT_ENABLED REG_BIT(17)
#define SLPC_BALANCER_IA_LMT_ACTIVE REG_BIT(18)
};
};
union {
u32 freq_padding;
struct {
#define SLPC_MAX_UNSLICE_FREQ_MASK REG_GENMASK(7, 0)
#define SLPC_MIN_UNSLICE_FREQ_MASK REG_GENMASK(15, 8)
#define SLPC_MAX_SLICE_FREQ_MASK REG_GENMASK(23, 16)
#define SLPC_MIN_SLICE_FREQ_MASK REG_GENMASK(31, 24)
u32 freq;
};
};
} __packed;
#define SLPC_CTX_FREQ_REQ_IS_COMPUTE REG_BIT(28)
#define SLPC_OPTIMIZED_STRATEGY_COMPUTE REG_BIT(0)
struct slpc_shared_data_header {
/* Total size in bytes of this shared buffer. */
u32 size;
u32 global_state;
u32 display_data_addr;
} __packed;
struct slpc_override_params {
u32 bits[SLPC_OVERRIDE_BITFIELD_SIZE];
u32 values[SLPC_MAX_OVERRIDE_PARAMETERS];
} __packed;
struct slpc_shared_data {
struct slpc_shared_data_header header;
u8 shared_data_header_pad[SLPC_SHARED_DATA_SIZE_BYTE_HEADER -
sizeof(struct slpc_shared_data_header)];
u8 platform_info_pad[SLPC_SHARED_DATA_SIZE_BYTE_PLATFORM_INFO];
struct slpc_task_state_data task_state_data;
u8 task_state_data_pad[SLPC_SHARED_DATA_SIZE_BYTE_TASK_STATE -
sizeof(struct slpc_task_state_data)];
struct slpc_override_params override_params;
u8 override_params_pad[SLPC_OVERRIDE_PARAMS_TOTAL_BYTES -
sizeof(struct slpc_override_params)];
u8 shared_data_pad[SLPC_SHARED_DATA_SIZE_BYTE_OTHER];
/* PAGE 2 (4096 bytes), mode based parameter will be removed soon */
u8 reserved_mode_definition[4096];
} __packed;
enum slpc_power_profile {
SLPC_POWER_PROFILE_BASE = 0x0,
SLPC_POWER_PROFILE_POWER_SAVING = 0x1
};
/**
* DOC: SLPC H2G MESSAGE FORMAT
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_HOST2GUC_PC_SLPM_REQUEST` = 0x3003 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:8 | **EVENT_ID** |
* + +-------+--------------------------------------------------------------+
* | | 7:0 | **EVENT_ARGC** - number of data arguments |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | **EVENT_DATA1** |
* +---+-------+--------------------------------------------------------------+
* |...| 31:0 | ... |
* +---+-------+--------------------------------------------------------------+
* |2+n| 31:0 | **EVENT_DATAn** |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_HOST2GUC_PC_SLPC_REQUEST 0x3003
#define HOST2GUC_PC_SLPC_REQUEST_MSG_MIN_LEN \
(GUC_HXG_REQUEST_MSG_MIN_LEN + 1u)
#define HOST2GUC_PC_SLPC_EVENT_MAX_INPUT_ARGS 9
#define HOST2GUC_PC_SLPC_REQUEST_MSG_MAX_LEN \
(HOST2GUC_PC_SLPC_REQUEST_REQUEST_MSG_MIN_LEN + \
HOST2GUC_PC_SLPC_EVENT_MAX_INPUT_ARGS)
#define HOST2GUC_PC_SLPC_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define HOST2GUC_PC_SLPC_REQUEST_MSG_1_EVENT_ID (0xffu << 8)
#define HOST2GUC_PC_SLPC_REQUEST_MSG_1_EVENT_ARGC (0xffu << 0)
#define HOST2GUC_PC_SLPC_REQUEST_MSG_N_EVENT_DATA_N GUC_HXG_REQUEST_MSG_n_DATAn
/**
* DOC: SETUP_PC_GUCRC
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_FAST_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_HOST2GUC_SETUP_PC_GUCRC` = 0x3004 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **MODE** = GUCRC_HOST_CONTROL(0), GUCRC_FIRMWARE_CONTROL(1) |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_HOST2GUC_SETUP_PC_GUCRC 0x3004u
#define GUCRC_HOST_CONTROL 0u
#define GUCRC_FIRMWARE_CONTROL 1u
#endif
@@ -0,0 +1,706 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _ABI_GUC_ACTIONS_SRIOV_ABI_H
#define _ABI_GUC_ACTIONS_SRIOV_ABI_H
#include "guc_communication_ctb_abi.h"
/**
* DOC: GUC2PF_RELAY_FROM_VF
*
* This message is used by the GuC firmware to forward a VF2PF `Relay Message`_
* received from the Virtual Function (VF) driver to this Physical Function (PF)
* driver.
*
* This message is always sent as `CTB HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_EVENT_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF` = 0x5100 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **VFID** - source VF identifier |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | **RELAY_ID** - VF/PF message ID |
* +---+-------+-----------------+--------------------------------------------+
* | 3 | 31:0 | **RELAY_DATA1** | |
* +---+-------+-----------------+ |
* |...| | | [Embedded `Relay Message`_] |
* +---+-------+-----------------+ |
* | n | 31:0 | **RELAY_DATAx** | |
* +---+-------+-----------------+--------------------------------------------+
*/
#define XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF 0x5100
#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN (GUC_HXG_EVENT_MSG_MIN_LEN + 2u)
#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_MAX_LEN \
(GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN + GUC_RELAY_MSG_MAX_LEN)
#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_0_MBZ GUC_HXG_EVENT_MSG_0_DATA0
#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_1_VFID GUC_HXG_EVENT_MSG_n_DATAn
#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_2_RELAY_ID GUC_HXG_EVENT_MSG_n_DATAn
#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_3_RELAY_DATA1 GUC_HXG_EVENT_MSG_n_DATAn
#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_n_RELAY_DATAx GUC_HXG_EVENT_MSG_n_DATAn
#define GUC2PF_RELAY_FROM_VF_EVENT_MSG_NUM_RELAY_DATA GUC_RELAY_MSG_MAX_LEN
/**
* DOC: PF2GUC_RELAY_TO_VF
*
* This H2G message is used by the Physical Function (PF) driver to send embedded
* VF2PF `Relay Message`_ to the VF.
*
* This action message must be sent over CTB as `CTB HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = `GUC_HXG_TYPE_FAST_REQUEST`_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`XE_GUC_ACTION_PF2GUC_RELAY_TO_VF` = 0x5101 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **VFID** - target VF identifier |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | **RELAY_ID** - VF/PF message ID |
* +---+-------+-----------------+--------------------------------------------+
* | 3 | 31:0 | **RELAY_DATA1** | |
* +---+-------+-----------------+ |
* |...| | | [Embedded `Relay Message`_] |
* +---+-------+-----------------+ |
* | n | 31:0 | **RELAY_DATAx** | |
* +---+-------+-----------------+--------------------------------------------+
*/
#define XE_GUC_ACTION_PF2GUC_RELAY_TO_VF 0x5101
#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 2u)
#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_MAX_LEN \
(PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN + GUC_RELAY_MSG_MAX_LEN)
#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_1_VFID GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_2_RELAY_ID GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_3_RELAY_DATA1 GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_n_RELAY_DATAx GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_RELAY_TO_VF_REQUEST_MSG_NUM_RELAY_DATA GUC_RELAY_MSG_MAX_LEN
/**
* DOC: GUC2VF_RELAY_FROM_PF
*
* This message is used by the GuC firmware to deliver `Relay Message`_ from the
* Physical Function (PF) driver to this Virtual Function (VF) driver.
* See `GuC Relay Communication`_ for details.
*
* This message is always sent over CTB.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_EVENT_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF` = 0x5102 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **RELAY_ID** - VF/PF message ID |
* +---+-------+-----------------+--------------------------------------------+
* | 2 | 31:0 | **RELAY_DATA1** | |
* +---+-------+-----------------+ |
* |...| | | [Embedded `Relay Message`_] |
* +---+-------+-----------------+ |
* | n | 31:0 | **RELAY_DATAx** | |
* +---+-------+-----------------+--------------------------------------------+
*/
#define XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF 0x5102
#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN (GUC_HXG_EVENT_MSG_MIN_LEN + 1u)
#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_MAX_LEN \
(GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN + GUC_RELAY_MSG_MAX_LEN)
#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_0_MBZ GUC_HXG_EVENT_MSG_0_DATA0
#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_1_RELAY_ID GUC_HXG_EVENT_MSG_n_DATAn
#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_n_RELAY_DATAx GUC_HXG_EVENT_MSG_n_DATAn
#define GUC2VF_RELAY_FROM_PF_EVENT_MSG_NUM_RELAY_DATA GUC_RELAY_MSG_MAX_LEN
/**
* DOC: VF2GUC_RELAY_TO_PF
*
* This message is used by the Virtual Function (VF) drivers to communicate with
* the Physical Function (PF) driver and send `Relay Message`_ to the PF driver.
* See `GuC Relay Communication`_ for details.
*
* This message must be sent over CTB.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ or GUC_HXG_TYPE_FAST_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`XE_GUC_ACTION_VF2GUC_RELAY_TO_PF` = 0x5103 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **RELAY_ID** - VF/PF message ID |
* +---+-------+-----------------+--------------------------------------------+
* | 2 | 31:0 | **RELAY_DATA1** | |
* +---+-------+-----------------+ |
* |...| | | [Embedded `Relay Message`_] |
* +---+-------+-----------------+ |
* | n | 31:0 | **RELAY_DATAx** | |
* +---+-------+-----------------+--------------------------------------------+
*/
#define XE_GUC_ACTION_VF2GUC_RELAY_TO_PF 0x5103
#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_MIN_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 1u)
#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_MAX_LEN \
(VF2GUC_RELAY_TO_PF_REQUEST_MSG_MIN_LEN + GUC_RELAY_MSG_MAX_LEN)
#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_1_RELAY_ID GUC_HXG_REQUEST_MSG_n_DATAn
#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_n_RELAY_DATAx GUC_HXG_REQUEST_MSG_n_DATAn
#define VF2GUC_RELAY_TO_PF_REQUEST_MSG_NUM_RELAY_DATA GUC_RELAY_MSG_MAX_LEN
/**
* DOC: GUC2PF_ADVERSE_EVENT
*
* This message is used by the GuC to notify PF about adverse events.
*
* This G2H message must be sent as `CTB HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_EVENT_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_GUC2PF_ADVERSE_EVENT` = 0x5104 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | DATA1 = **VFID** - VF identifier |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | DATA2 = **THRESHOLD** - key of the exceeded threshold |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_GUC2PF_ADVERSE_EVENT 0x5104
#define GUC2PF_ADVERSE_EVENT_EVENT_MSG_LEN (GUC_HXG_EVENT_MSG_MIN_LEN + 2u)
#define GUC2PF_ADVERSE_EVENT_EVENT_MSG_0_MBZ GUC_HXG_EVENT_MSG_0_DATA0
#define GUC2PF_ADVERSE_EVENT_EVENT_MSG_1_VFID GUC_HXG_EVENT_MSG_n_DATAn
#define GUC2PF_ADVERSE_EVENT_EVENT_MSG_2_THRESHOLD GUC_HXG_EVENT_MSG_n_DATAn
/**
* DOC: GUC2PF_VF_STATE_NOTIFY
*
* The GUC2PF_VF_STATE_NOTIFY message is used by the GuC to notify PF about change
* of the VF state.
*
* This G2H message is sent as `CTB HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_EVENT_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_GUC2PF_VF_STATE_NOTIFY` = 0x5106 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | DATA1 = **VFID** - VF identifier |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | DATA2 = **EVENT** - notification event: |
* | | | |
* | | | - _`GUC_PF_NOTIFY_VF_ENABLE` = 1 (only if VFID = 0) |
* | | | - _`GUC_PF_NOTIFY_VF_FLR` = 1 |
* | | | - _`GUC_PF_NOTIFY_VF_FLR_DONE` = 2 |
* | | | - _`GUC_PF_NOTIFY_VF_PAUSE_DONE` = 3 |
* | | | - _`GUC_PF_NOTIFY_VF_FIXUP_DONE` = 4 |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_GUC2PF_VF_STATE_NOTIFY 0x5106u
#define GUC2PF_VF_STATE_NOTIFY_EVENT_MSG_LEN (GUC_HXG_EVENT_MSG_MIN_LEN + 2u)
#define GUC2PF_VF_STATE_NOTIFY_EVENT_MSG_0_MBZ GUC_HXG_EVENT_MSG_0_DATA0
#define GUC2PF_VF_STATE_NOTIFY_EVENT_MSG_1_VFID GUC_HXG_EVENT_MSG_n_DATAn
#define GUC2PF_VF_STATE_NOTIFY_EVENT_MSG_2_EVENT GUC_HXG_EVENT_MSG_n_DATAn
#define GUC_PF_NOTIFY_VF_ENABLE 1u
#define GUC_PF_NOTIFY_VF_FLR 1u
#define GUC_PF_NOTIFY_VF_FLR_DONE 2u
#define GUC_PF_NOTIFY_VF_PAUSE_DONE 3u
#define GUC_PF_NOTIFY_VF_FIXUP_DONE 4u
/**
* DOC: VF2GUC_MATCH_VERSION
*
* This action is used to match VF interface version used by VF and GuC.
*
* This message must be sent as `MMIO HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_VF2GUC_MATCH_VERSION` = 0x5500 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:24 | **BRANCH** - branch ID of the VF interface |
* | | | (use BRANCH_ANY to request latest version supported by GuC) |
* | +-------+--------------------------------------------------------------+
* | | 23:16 | **MAJOR** - major version of the VF interface |
* | | | (use MAJOR_ANY to request latest version supported by GuC) |
* | +-------+--------------------------------------------------------------+
* | | 15:8 | **MINOR** - minor version of the VF interface |
* | | | (use MINOR_ANY to request latest version supported by GuC) |
* | +-------+--------------------------------------------------------------+
* | | 7:0 | **MBZ** |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = MBZ |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:24 | **BRANCH** - branch ID of the VF interface |
* | +-------+--------------------------------------------------------------+
* | | 23:16 | **MAJOR** - major version of the VF interface |
* | +-------+--------------------------------------------------------------+
* | | 15:8 | **MINOR** - minor version of the VF interface |
* | +-------+--------------------------------------------------------------+
* | | 7:0 | **PATCH** - patch version of the VF interface |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_VF2GUC_MATCH_VERSION 0x5500u
#define VF2GUC_MATCH_VERSION_REQUEST_MSG_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 1u)
#define VF2GUC_MATCH_VERSION_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define VF2GUC_MATCH_VERSION_REQUEST_MSG_1_BRANCH (0xffu << 24)
#define GUC_VERSION_BRANCH_ANY 0
#define VF2GUC_MATCH_VERSION_REQUEST_MSG_1_MAJOR (0xffu << 16)
#define GUC_VERSION_MAJOR_ANY 0
#define VF2GUC_MATCH_VERSION_REQUEST_MSG_1_MINOR (0xffu << 8)
#define GUC_VERSION_MINOR_ANY 0
#define VF2GUC_MATCH_VERSION_REQUEST_MSG_1_MBZ (0xffu << 0)
#define VF2GUC_MATCH_VERSION_RESPONSE_MSG_LEN (GUC_HXG_RESPONSE_MSG_MIN_LEN + 1u)
#define VF2GUC_MATCH_VERSION_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0
#define VF2GUC_MATCH_VERSION_RESPONSE_MSG_1_BRANCH (0xffu << 24)
#define VF2GUC_MATCH_VERSION_RESPONSE_MSG_1_MAJOR (0xffu << 16)
#define VF2GUC_MATCH_VERSION_RESPONSE_MSG_1_MINOR (0xffu << 8)
#define VF2GUC_MATCH_VERSION_RESPONSE_MSG_1_PATCH (0xffu << 0)
/**
* DOC: PF2GUC_UPDATE_VGT_POLICY
*
* This message is used by the PF to set `GuC VGT Policy KLVs`_.
*
* This message must be sent as `CTB HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_PF2GUC_UPDATE_VGT_POLICY` = 0x5502 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **CFG_ADDR_LO** - dword aligned GGTT offset that |
* | | | represents the start of `GuC VGT Policy KLVs`_ list. |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | **CFG_ADDR_HI** - upper 32 bits of above offset. |
* +---+-------+--------------------------------------------------------------+
* | 3 | 31:0 | **CFG_SIZE** - size (in dwords) of the config buffer |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | **COUNT** - number of KLVs successfully applied |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_PF2GUC_UPDATE_VGT_POLICY 0x5502u
#define PF2GUC_UPDATE_VGT_POLICY_REQUEST_MSG_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 3u)
#define PF2GUC_UPDATE_VGT_POLICY_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define PF2GUC_UPDATE_VGT_POLICY_REQUEST_MSG_1_CFG_ADDR_LO GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_UPDATE_VGT_POLICY_REQUEST_MSG_2_CFG_ADDR_HI GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_UPDATE_VGT_POLICY_REQUEST_MSG_3_CFG_SIZE GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_UPDATE_VGT_POLICY_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN
#define PF2GUC_UPDATE_VGT_POLICY_RESPONSE_MSG_0_COUNT GUC_HXG_RESPONSE_MSG_0_DATA0
/**
* DOC: PF2GUC_UPDATE_VF_CFG
*
* The `PF2GUC_UPDATE_VF_CFG`_ message is used by PF to provision single VF in GuC.
*
* This message must be sent as `CTB HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_PF2GUC_UPDATE_VF_CFG` = 0x5503 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **VFID** - identifier of the VF that the KLV |
* | | | configurations are being applied to |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | **CFG_ADDR_LO** - dword aligned GGTT offset that represents |
* | | | the start of a list of virtualization related KLV configs |
* | | | that are to be applied to the VF. |
* | | | If this parameter is zero, the list is not parsed. |
* | | | If full configs address parameter is zero and configs_size is|
* | | | zero associated VF config shall be reset to its default state|
* +---+-------+--------------------------------------------------------------+
* | 3 | 31:0 | **CFG_ADDR_HI** - upper 32 bits of configs address. |
* +---+-------+--------------------------------------------------------------+
* | 4 | 31:0 | **CFG_SIZE** - size (in dwords) of the config buffer |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | **COUNT** - number of KLVs successfully applied |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_PF2GUC_UPDATE_VF_CFG 0x5503u
#define PF2GUC_UPDATE_VF_CFG_REQUEST_MSG_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 4u)
#define PF2GUC_UPDATE_VF_CFG_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define PF2GUC_UPDATE_VF_CFG_REQUEST_MSG_1_VFID GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_UPDATE_VF_CFG_REQUEST_MSG_2_CFG_ADDR_LO GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_UPDATE_VF_CFG_REQUEST_MSG_3_CFG_ADDR_HI GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_UPDATE_VF_CFG_REQUEST_MSG_4_CFG_SIZE GUC_HXG_REQUEST_MSG_n_DATAn
#define PF2GUC_UPDATE_VF_CFG_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN
#define PF2GUC_UPDATE_VF_CFG_RESPONSE_MSG_0_COUNT GUC_HXG_RESPONSE_MSG_0_DATA0
/**
* DOC: PF2GUC_VF_CONTROL
*
* The PF2GUC_VF_CONTROL message is used by the PF to trigger VF state change
* maintained by the GuC.
*
* This H2G message must be sent as `CTB HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_PF2GUC_VF_CONTROL_CMD` = 0x5506 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | DATA1 = **VFID** - VF identifier |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | DATA2 = **COMMAND** - control command: |
* | | | |
* | | | - _`GUC_PF_TRIGGER_VF_PAUSE` = 1 |
* | | | - _`GUC_PF_TRIGGER_VF_RESUME` = 2 |
* | | | - _`GUC_PF_TRIGGER_VF_STOP` = 3 |
* | | | - _`GUC_PF_TRIGGER_VF_FLR_START` = 4 |
* | | | - _`GUC_PF_TRIGGER_VF_FLR_FINISH` = 5 |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = MBZ |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_PF2GUC_VF_CONTROL 0x5506u
#define PF2GUC_VF_CONTROL_REQUEST_MSG_LEN (GUC_HXG_EVENT_MSG_MIN_LEN + 2u)
#define PF2GUC_VF_CONTROL_REQUEST_MSG_0_MBZ GUC_HXG_EVENT_MSG_0_DATA0
#define PF2GUC_VF_CONTROL_REQUEST_MSG_1_VFID GUC_HXG_EVENT_MSG_n_DATAn
#define PF2GUC_VF_CONTROL_REQUEST_MSG_2_COMMAND GUC_HXG_EVENT_MSG_n_DATAn
#define GUC_PF_TRIGGER_VF_PAUSE 1u
#define GUC_PF_TRIGGER_VF_RESUME 2u
#define GUC_PF_TRIGGER_VF_STOP 3u
#define GUC_PF_TRIGGER_VF_FLR_START 4u
#define GUC_PF_TRIGGER_VF_FLR_FINISH 5u
/**
* DOC: VF2GUC_VF_RESET
*
* This action is used by VF to reset GuC's VF state.
*
* This message must be sent as `MMIO HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_VF2GUC_VF_RESET` = 0x5507 |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = MBZ |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_VF2GUC_VF_RESET 0x5507u
#define VF2GUC_VF_RESET_REQUEST_MSG_LEN GUC_HXG_REQUEST_MSG_MIN_LEN
#define VF2GUC_VF_RESET_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define VF2GUC_VF_RESET_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN
#define VF2GUC_VF_RESET_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0
/**
* DOC: VF2GUC_RESFIX_DONE
*
* This action is used by VF to inform the GuC that the VF KMD has completed
* post-migration recovery steps. From GuC VF compatibility 1.27.0 onwards, it
* shall only be sent after posting RESFIX_START and that both @MARKER fields
* must match.
*
* This message must be sent as `MMIO HXG Message`_.
*
* Updated since GuC VF compatibility 1.27.0.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MARKER = MBZ (only prior 1.27.0) |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MARKER - can't be zero (1.27.0+) |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_VF2GUC_RESFIX_DONE` = 0x5508 |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = MBZ |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_VF2GUC_RESFIX_DONE 0x5508u
#define VF2GUC_RESFIX_DONE_REQUEST_MSG_LEN GUC_HXG_REQUEST_MSG_MIN_LEN
#define VF2GUC_RESFIX_DONE_REQUEST_MSG_0_MARKER GUC_HXG_REQUEST_MSG_0_DATA0
#define VF2GUC_RESFIX_DONE_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN
#define VF2GUC_RESFIX_DONE_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0
/**
* DOC: VF2GUC_QUERY_SINGLE_KLV
*
* This action is used by VF to query value of the single KLV data.
*
* This message must be sent as `MMIO HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_VF2GUC_QUERY_SINGLE_KLV` = 0x5509 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:16 | MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | **KEY** - key for which value is requested |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | **LENGTH** - length of data in dwords |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **VALUE32** - bits 31:0 of value if **LENGTH** >= 1 |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | **VALUE64** - bits 63:32 of value if **LENGTH** >= 2 |
* +---+-------+--------------------------------------------------------------+
* | 3 | 31:0 | **VALUE96** - bits 95:64 of value if **LENGTH** >= 3 |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_VF2GUC_QUERY_SINGLE_KLV 0x5509u
#define VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_LEN (GUC_HXG_REQUEST_MSG_MIN_LEN + 1u)
#define VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_1_MBZ (0xffffu << 16)
#define VF2GUC_QUERY_SINGLE_KLV_REQUEST_MSG_1_KEY (0xffffu << 0)
#define VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_MIN_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN
#define VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_MAX_LEN (GUC_HXG_RESPONSE_MSG_MIN_LEN + 3u)
#define VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_0_MBZ (0xfffu << 16)
#define VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_0_LENGTH (0xffffu << 0)
#define VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_1_VALUE32 GUC_HXG_REQUEST_MSG_n_DATAn
#define VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_2_VALUE64 GUC_HXG_REQUEST_MSG_n_DATAn
#define VF2GUC_QUERY_SINGLE_KLV_RESPONSE_MSG_3_VALUE96 GUC_HXG_REQUEST_MSG_n_DATAn
/**
* DOC: PF2GUC_SAVE_RESTORE_VF
*
* This message is used by the PF to migrate VF info state maintained by the GuC.
*
* This message must be sent as `CTB HXG Message`_.
*
* Available since GuC version 70.25.0
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = **OPCODE** - operation to take: |
* | | | |
* | | | - _`GUC_PF_OPCODE_VF_SAVE` = 0 |
* | | | - _`GUC_PF_OPCODE_VF_RESTORE` = 1 |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_PF2GUC_SAVE_RESTORE_VF` = 0x550B |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **VFID** - VF identifier |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | **ADDR_LO** - lower 32-bits of GGTT offset to the buffer |
* | | | where the VF info will be save to or restored from. |
* +---+-------+--------------------------------------------------------------+
* | 3 | 31:0 | **ADDR_HI** - upper 32-bits of GGTT offset to the buffer |
* | | | where the VF info will be save to or restored from. |
* +---+-------+--------------------------------------------------------------+
* | 4 | 27:0 | **SIZE** - size of the buffer (in dwords) |
* | +-------+--------------------------------------------------------------+
* | | 31:28 | MBZ |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = **USED** - size of used buffer space (in dwords) |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_PF2GUC_SAVE_RESTORE_VF 0x550Bu
#define PF2GUC_SAVE_RESTORE_VF_REQUEST_MSG_LEN (GUC_HXG_EVENT_MSG_MIN_LEN + 4u)
#define PF2GUC_SAVE_RESTORE_VF_REQUEST_MSG_0_OPCODE GUC_HXG_EVENT_MSG_0_DATA0
#define GUC_PF_OPCODE_VF_SAVE 0u
#define GUC_PF_OPCODE_VF_RESTORE 1u
#define PF2GUC_SAVE_RESTORE_VF_REQUEST_MSG_1_VFID GUC_HXG_EVENT_MSG_n_DATAn
#define PF2GUC_SAVE_RESTORE_VF_REQUEST_MSG_2_ADDR_LO GUC_HXG_EVENT_MSG_n_DATAn
#define PF2GUC_SAVE_RESTORE_VF_REQUEST_MSG_3_ADDR_HI GUC_HXG_EVENT_MSG_n_DATAn
#define PF2GUC_SAVE_RESTORE_VF_REQUEST_MSG_4_SIZE (0xfffffffu << 0)
#define PF2GUC_SAVE_RESTORE_VF_REQUEST_MSG_4_MBZ (0xfu << 28)
#define PF2GUC_SAVE_RESTORE_VF_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN
#define PF2GUC_SAVE_RESTORE_VF_RESPONSE_MSG_0_USED GUC_HXG_RESPONSE_MSG_0_DATA0
/**
* DOC: VF2GUC_RESFIX_START
*
* This action is used by VF to inform the GuC that the VF KMD will be starting
* post-migration recovery fixups. The @MARKER sent with this action must match
* with the MARKER posted in the VF2GUC_RESFIX_DONE message.
*
* This message must be sent as `MMIO HXG Message`_.
*
* Available since GuC VF compatibility 1.27.0.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MARKER - can't be zero |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_ACTION_VF2GUC_RESFIX_START` = 0x550F |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = MBZ |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_ACTION_VF2GUC_RESFIX_START 0x550Fu
#define VF2GUC_RESFIX_START_REQUEST_MSG_LEN GUC_HXG_REQUEST_MSG_MIN_LEN
#define VF2GUC_RESFIX_START_REQUEST_MSG_0_MARKER GUC_HXG_REQUEST_MSG_0_DATA0
#define VF2GUC_RESFIX_START_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN
#define VF2GUC_RESFIX_START_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0
#endif
@@ -0,0 +1,186 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef _ABI_GUC_CAPTURE_ABI_H
#define _ABI_GUC_CAPTURE_ABI_H
#include <linux/types.h>
/* Capture List Index */
enum guc_capture_list_index_type {
GUC_CAPTURE_LIST_INDEX_PF = 0,
GUC_CAPTURE_LIST_INDEX_VF = 1,
};
#define GUC_CAPTURE_LIST_INDEX_MAX (GUC_CAPTURE_LIST_INDEX_VF + 1)
/* Register-types of GuC capture register lists */
enum guc_state_capture_type {
GUC_STATE_CAPTURE_TYPE_GLOBAL = 0,
GUC_STATE_CAPTURE_TYPE_ENGINE_CLASS,
GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE
};
#define GUC_STATE_CAPTURE_TYPE_MAX (GUC_STATE_CAPTURE_TYPE_ENGINE_INSTANCE + 1)
/* Class indices for capture_class and capture_instance arrays */
enum guc_capture_list_class_type {
GUC_CAPTURE_LIST_CLASS_RENDER_COMPUTE = 0,
GUC_CAPTURE_LIST_CLASS_VIDEO = 1,
GUC_CAPTURE_LIST_CLASS_VIDEOENHANCE = 2,
GUC_CAPTURE_LIST_CLASS_BLITTER = 3,
GUC_CAPTURE_LIST_CLASS_GSC_OTHER = 4,
};
#define GUC_CAPTURE_LIST_CLASS_MAX (GUC_CAPTURE_LIST_CLASS_GSC_OTHER + 1)
/**
* struct guc_mmio_reg - GuC MMIO reg state struct
*
* GuC MMIO reg state struct
*/
struct guc_mmio_reg {
/** @offset: MMIO Offset - filled in by Host */
u32 offset;
/** @value: MMIO Value - Used by Firmware to store value */
u32 value;
/** @flags: Flags for accessing the MMIO */
u32 flags;
/** @mask: Value of a mask to apply if mask with value is set */
u32 mask;
#define GUC_REGSET_MASKED BIT(0)
#define GUC_REGSET_STEERING_NEEDED BIT(1)
#define GUC_REGSET_MASKED_WITH_VALUE BIT(2)
#define GUC_REGSET_RESTORE_ONLY BIT(3)
#define GUC_REGSET_STEERING_GROUP GENMASK(16, 12)
#define GUC_REGSET_STEERING_INSTANCE GENMASK(23, 20)
} __packed;
/**
* struct guc_mmio_reg_set - GuC register sets
*
* GuC register sets
*/
struct guc_mmio_reg_set {
/** @address: register address */
u32 address;
/** @count: register count */
u16 count;
/** @reserved: reserved */
u16 reserved;
} __packed;
/**
* struct guc_debug_capture_list_header - Debug capture list header.
*
* Debug capture list header.
*/
struct guc_debug_capture_list_header {
/** @info: contains number of MMIO descriptors in the capture list. */
u32 info;
#define GUC_CAPTURELISTHDR_NUMDESCR GENMASK(15, 0)
} __packed;
/**
* struct guc_debug_capture_list - Debug capture list
*
* As part of ADS registration, these header structures (followed by
* an array of 'struct guc_mmio_reg' entries) are used to register with
* GuC microkernel the list of registers we want it to dump out prior
* to a engine reset.
*/
struct guc_debug_capture_list {
/** @header: Debug capture list header. */
struct guc_debug_capture_list_header header;
/** @regs: MMIO descriptors in the capture list. */
struct guc_mmio_reg regs[];
} __packed;
/**
* struct guc_state_capture_header_t - State capture header.
*
* Prior to resetting engines that have hung or faulted, GuC microkernel
* reports the engine error-state (register values that was read) by
* logging them into the shared GuC log buffer using these hierarchy
* of structures.
*/
struct guc_state_capture_header_t {
/**
* @owner: VFID
* BR[ 7: 0] MBZ when SRIOV is disabled. When SRIOV is enabled
* VFID is an integer in range [0, 63] where 0 means the state capture
* is corresponding to the PF and an integer N in range [1, 63] means
* the state capture is for VF N.
*/
u32 owner;
#define GUC_STATE_CAPTURE_HEADER_VFID GENMASK(7, 0)
/** @info: Engine class/instance and capture type info */
u32 info;
#define GUC_STATE_CAPTURE_HEADER_CAPTURE_TYPE GENMASK(3, 0) /* see guc_state_capture_type */
#define GUC_STATE_CAPTURE_HEADER_ENGINE_CLASS GENMASK(7, 4) /* see guc_capture_list_class_type */
#define GUC_STATE_CAPTURE_HEADER_ENGINE_INSTANCE GENMASK(11, 8)
/**
* @lrca: logical ring context address.
* if type-instance, LRCA (address) that hung, else set to ~0
*/
u32 lrca;
/**
* @guc_id: context_index.
* if type-instance, context index of hung context, else set to ~0
*/
u32 guc_id;
/** @num_mmio_entries: Number of captured MMIO entries. */
u32 num_mmio_entries;
#define GUC_STATE_CAPTURE_HEADER_NUM_MMIO_ENTRIES GENMASK(9, 0)
} __packed;
/**
* struct guc_state_capture_t - State capture.
*
* State capture
*/
struct guc_state_capture_t {
/** @header: State capture header. */
struct guc_state_capture_header_t header;
/** @mmio_entries: Array of captured guc_mmio_reg entries. */
struct guc_mmio_reg mmio_entries[];
} __packed;
/* State Capture Group Type */
enum guc_state_capture_group_type {
GUC_STATE_CAPTURE_GROUP_TYPE_FULL = 0,
GUC_STATE_CAPTURE_GROUP_TYPE_PARTIAL
};
#define GUC_STATE_CAPTURE_GROUP_TYPE_MAX (GUC_STATE_CAPTURE_GROUP_TYPE_PARTIAL + 1)
/**
* struct guc_state_capture_group_header_t - State capture group header
*
* State capture group header.
*/
struct guc_state_capture_group_header_t {
/** @owner: VFID */
u32 owner;
#define GUC_STATE_CAPTURE_GROUP_HEADER_VFID GENMASK(7, 0)
/** @info: Engine class/instance and capture type info */
u32 info;
#define GUC_STATE_CAPTURE_GROUP_HEADER_NUM_CAPTURES GENMASK(7, 0)
#define GUC_STATE_CAPTURE_GROUP_HEADER_CAPTURE_GROUP_TYPE GENMASK(15, 8)
} __packed;
/**
* struct guc_state_capture_group_t - State capture group.
*
* this is the top level structure where an error-capture dump starts
*/
struct guc_state_capture_group_t {
/** @grp_header: State capture group header. */
struct guc_state_capture_group_header_t grp_header;
/** @capture_entries: Array of state captures */
struct guc_state_capture_t capture_entries[];
} __packed;
#endif
@@ -0,0 +1,129 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2014-2021 Intel Corporation
*/
#ifndef _ABI_GUC_COMMUNICATION_CTB_ABI_H
#define _ABI_GUC_COMMUNICATION_CTB_ABI_H
#include <linux/types.h>
#include <linux/build_bug.h>
#include "guc_messages_abi.h"
/**
* DOC: CT Buffer
*
* Circular buffer used to send `CTB Message`_
*/
/**
* DOC: CTB Descriptor
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31:0 | **HEAD** - offset (in dwords) to the last dword that was |
* | | | read from the `CT Buffer`_. |
* | | | It can only be updated by the receiver. |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **TAIL** - offset (in dwords) to the last dword that was |
* | | | written to the `CT Buffer`_. |
* | | | It can only be updated by the sender. |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | **STATUS** - status of the CTB |
* | | | |
* | | | - _`GUC_CTB_STATUS_NO_ERROR` = 0 (normal operation) |
* | | | - _`GUC_CTB_STATUS_OVERFLOW` = 1 (head/tail too large) |
* | | | - _`GUC_CTB_STATUS_UNDERFLOW` = 2 (truncated message) |
* | | | - _`GUC_CTB_STATUS_MISMATCH` = 4 (head/tail modified) |
* +---+-------+--------------------------------------------------------------+
* |...| | RESERVED = MBZ |
* +---+-------+--------------------------------------------------------------+
* | 15| 31:0 | RESERVED = MBZ |
* +---+-------+--------------------------------------------------------------+
*/
struct guc_ct_buffer_desc {
u32 head;
u32 tail;
u32 status;
#define GUC_CTB_STATUS_NO_ERROR 0
#define GUC_CTB_STATUS_OVERFLOW (1 << 0)
#define GUC_CTB_STATUS_UNDERFLOW (1 << 1)
#define GUC_CTB_STATUS_MISMATCH (1 << 2)
#define GUC_CTB_STATUS_DISABLED (1 << 3)
u32 reserved[13];
} __packed;
static_assert(sizeof(struct guc_ct_buffer_desc) == 64);
/**
* DOC: CTB Message
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31:16 | **FENCE** - message identifier |
* | +-------+--------------------------------------------------------------+
* | | 15:12 | **FORMAT** - format of the CTB message |
* | | | - _`GUC_CTB_FORMAT_HXG` = 0 - see `CTB HXG Message`_ |
* | +-------+--------------------------------------------------------------+
* | | 11:8 | **RESERVED** |
* | +-------+--------------------------------------------------------------+
* | | 7:0 | **NUM_DWORDS** - length of the CTB message (w/o header) |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | optional (depends on FORMAT) |
* +---+-------+ |
* |...| | |
* +---+-------+ |
* | n | 31:0 | |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_CTB_HDR_LEN 1u
#define GUC_CTB_MSG_MIN_LEN GUC_CTB_HDR_LEN
#define GUC_CTB_MSG_MAX_LEN (GUC_CTB_MSG_MIN_LEN + GUC_CTB_MAX_DWORDS)
#define GUC_CTB_MSG_0_FENCE (0xffffu << 16)
#define GUC_CTB_MSG_0_FORMAT (0xfu << 12)
#define GUC_CTB_FORMAT_HXG 0u
#define GUC_CTB_MSG_0_RESERVED (0xfu << 8)
#define GUC_CTB_MSG_0_NUM_DWORDS (0xffu << 0)
#define GUC_CTB_MAX_DWORDS 255
/**
* DOC: CTB HXG Message
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31:16 | FENCE |
* | +-------+--------------------------------------------------------------+
* | | 15:12 | FORMAT = GUC_CTB_FORMAT_HXG_ |
* | +-------+--------------------------------------------------------------+
* | | 11:8 | RESERVED = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 7:0 | NUM_DWORDS = length (in dwords) of the embedded HXG message |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | |
* +---+-------+ |
* |...| | [Embedded `HXG Message`_] |
* +---+-------+ |
* | n | 31:0 | |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_CTB_HXG_MSG_MIN_LEN (GUC_CTB_MSG_MIN_LEN + GUC_HXG_MSG_MIN_LEN)
#define GUC_CTB_HXG_MSG_MAX_LEN GUC_CTB_MSG_MAX_LEN
/**
* DOC: CTB based communication
*
* The CTB (command transport buffer) communication between Host and GuC
* is based on u32 data stream written to the shared buffer. One buffer can
* be used to transmit data only in one direction (one-directional channel).
*
* Current status of the each buffer is maintained in the `CTB Descriptor`_.
* Each message in data stream is encoded as `CTB HXG Message`_.
*/
#endif
@@ -0,0 +1,49 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2014-2021 Intel Corporation
*/
#ifndef _ABI_GUC_COMMUNICATION_MMIO_ABI_H
#define _ABI_GUC_COMMUNICATION_MMIO_ABI_H
/**
* DOC: GuC MMIO based communication
*
* The MMIO based communication between Host and GuC relies on special
* hardware registers which format could be defined by the software
* (so called scratch registers).
*
* Each MMIO based message, both Host to GuC (H2G) and GuC to Host (G2H)
* messages, which maximum length depends on number of available scratch
* registers, is directly written into those scratch registers.
*
* For Gen9+, there are 16 software scratch registers 0xC180-0xC1B8,
* but no H2G command takes more than 4 parameters and the GuC firmware
* itself uses an 4-element array to store the H2G message.
*
* For Gen11+, there are additional 4 registers 0x190240-0x19024C, which
* are, regardless on lower count, preferred over legacy ones.
*
* The MMIO based communication is mainly used during driver initialization
* phase to setup the `CTB based communication`_ that will be used afterwards.
*/
#define GUC_MAX_MMIO_MSG_LEN 4
/**
* DOC: MMIO HXG Message
*
* Format of the MMIO messages follows definitions of `HXG Message`_.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31:0 | |
* +---+-------+ |
* |...| | [Embedded `HXG Message`_] |
* +---+-------+ |
* | n | 31:0 | |
* +---+-------+--------------------------------------------------------------+
*/
#endif
@@ -0,0 +1,101 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2014-2021 Intel Corporation
*/
#ifndef _ABI_GUC_ERRORS_ABI_H
#define _ABI_GUC_ERRORS_ABI_H
enum xe_guc_response {
XE_GUC_RESPONSE_ERROR_PROTOCOL = 0x04,
XE_GUC_RESPONSE_INVALID_STATE = 0x0A,
XE_GUC_RESPONSE_UNSUPPORTED_VERSION = 0x0B,
XE_GUC_RESPONSE_INVALID_VFID = 0x0C,
XE_GUC_RESPONSE_UNPROVISIONED_VF = 0x0D,
XE_GUC_RESPONSE_INVALID_EVENT = 0x0E,
XE_GUC_RESPONSE_NOT_SUPPORTED = 0x20,
XE_GUC_RESPONSE_UNKNOWN_ACTION = 0x30,
XE_GUC_RESPONSE_ACTION_ABORTED = 0x31,
XE_GUC_RESPONSE_NO_PERMISSION = 0x40,
XE_GUC_RESPONSE_CANNOT_COMPLETE_ACTION = 0x41,
XE_GUC_RESPONSE_INVALID_KLV_DATA = 0x50,
XE_GUC_RESPONSE_INVALID_PARAMS = 0x60,
XE_GUC_RESPONSE_INVALID_CONTEXT_INDEX = 0x61,
XE_GUC_RESPONSE_INVALID_CONTEXT_REGISTRATION = 0x62,
XE_GUC_RESPONSE_INVALID_DOORBELL_ID = 0x63,
XE_GUC_RESPONSE_INVALID_ENGINE_ID = 0x64,
XE_GUC_RESPONSE_INVALID_BUFFER_RANGE = 0x70,
XE_GUC_RESPONSE_INVALID_BUFFER = 0x71,
XE_GUC_RESPONSE_BUFFER_ALREADY_REGISTERED = 0x72,
XE_GUC_RESPONSE_INVALID_GGTT_ADDRESS = 0x80,
XE_GUC_RESPONSE_PENDING_ACTION = 0x90,
XE_GUC_RESPONSE_CONTEXT_NOT_REGISTERED = 0x100,
XE_GUC_RESPONSE_CONTEXT_ALREADY_REGISTERED = 0X101,
XE_GUC_RESPONSE_INVALID_SIZE = 0x102,
XE_GUC_RESPONSE_MALFORMED_KLV = 0x103,
XE_GUC_RESPONSE_INVALID_CONTEXT = 0x104,
XE_GUC_RESPONSE_INVALID_KLV_KEY = 0x105,
XE_GUC_RESPONSE_DATA_TOO_LARGE = 0x106,
XE_GUC_RESPONSE_VF_MIGRATED = 0x107,
XE_GUC_RESPONSE_NO_ATTRIBUTE_TABLE = 0x201,
XE_GUC_RESPONSE_NO_DECRYPTION_KEY = 0x202,
XE_GUC_RESPONSE_DECRYPTION_FAILED = 0x204,
XE_GUC_RESPONSE_VGT_DISABLED = 0x300,
XE_GUC_RESPONSE_CTB_FULL = 0x301,
XE_GUC_RESPONSE_VGT_UNAUTHORIZED_REQUEST = 0x302,
XE_GUC_RESPONSE_CTB_INVALID = 0x303,
XE_GUC_RESPONSE_CTB_NOT_REGISTERED = 0x304,
XE_GUC_RESPONSE_CTB_IN_USE = 0x305,
XE_GUC_RESPONSE_CTB_INVALID_DESC = 0x306,
XE_GUC_RESPONSE_HW_TIMEOUT = 0x30C,
XE_GUC_RESPONSE_CTB_SOURCE_INVALID_DESCRIPTOR = 0x30D,
XE_GUC_RESPONSE_CTB_DESTINATION_INVALID_DESCRIPTOR = 0x30E,
XE_GUC_RESPONSE_INVALID_CONFIG_STATE = 0x30F,
XE_GUC_RESPONSE_GENERIC_FAIL = 0xF000,
};
enum xe_guc_load_status {
XE_GUC_LOAD_STATUS_DEFAULT = 0x00,
XE_GUC_LOAD_STATUS_START = 0x01,
XE_GUC_LOAD_STATUS_ERROR_DEVID_BUILD_MISMATCH = 0x02,
XE_GUC_LOAD_STATUS_GUC_PREPROD_BUILD_MISMATCH = 0x03,
XE_GUC_LOAD_STATUS_ERROR_DEVID_INVALID_GUCTYPE = 0x04,
XE_GUC_LOAD_STATUS_HWCONFIG_START = 0x05,
XE_GUC_LOAD_STATUS_HWCONFIG_DONE = 0x06,
XE_GUC_LOAD_STATUS_HWCONFIG_ERROR = 0x07,
XE_GUC_LOAD_STATUS_BOOTROM_VERSION_MISMATCH = 0x08,
XE_GUC_LOAD_STATUS_GDT_DONE = 0x10,
XE_GUC_LOAD_STATUS_IDT_DONE = 0x20,
XE_GUC_LOAD_STATUS_LAPIC_DONE = 0x30,
XE_GUC_LOAD_STATUS_GUCINT_DONE = 0x40,
XE_GUC_LOAD_STATUS_DPC_READY = 0x50,
XE_GUC_LOAD_STATUS_DPC_ERROR = 0x60,
XE_GUC_LOAD_STATUS_EXCEPTION = 0x70,
XE_GUC_LOAD_STATUS_INIT_DATA_INVALID = 0x71,
XE_GUC_LOAD_STATUS_PXP_TEARDOWN_CTRL_ENABLED = 0x72,
XE_GUC_LOAD_STATUS_INVALID_INIT_DATA_RANGE_START,
XE_GUC_LOAD_STATUS_MPU_DATA_INVALID = 0x73,
XE_GUC_LOAD_STATUS_INIT_MMIO_SAVE_RESTORE_INVALID = 0x74,
XE_GUC_LOAD_STATUS_KLV_WORKAROUND_INIT_ERROR = 0x75,
XE_GUC_LOAD_STATUS_INVALID_FTR_FLAG = 0x76,
XE_GUC_LOAD_STATUS_INVALID_INIT_DATA_RANGE_END,
XE_GUC_LOAD_STATUS_READY = 0xF0,
};
enum xe_bootrom_load_status {
XE_BOOTROM_STATUS_NO_KEY_FOUND = 0x13,
XE_BOOTROM_STATUS_AES_PROD_KEY_FOUND = 0x1A,
XE_BOOTROM_STATUS_PROD_KEY_CHECK_FAILURE = 0x2B,
XE_BOOTROM_STATUS_RSA_FAILED = 0x50,
XE_BOOTROM_STATUS_PAVPC_FAILED = 0x73,
XE_BOOTROM_STATUS_WOPCM_FAILED = 0x74,
XE_BOOTROM_STATUS_LOADLOC_FAILED = 0x75,
XE_BOOTROM_STATUS_JUMP_PASSED = 0x76,
XE_BOOTROM_STATUS_JUMP_FAILED = 0x77,
XE_BOOTROM_STATUS_RC6CTXCONFIG_FAILED = 0x79,
XE_BOOTROM_STATUS_MPUMAP_INCORRECT = 0x7A,
XE_BOOTROM_STATUS_EXCEPTION = 0x7E,
};
#endif
@@ -0,0 +1,509 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2021 Intel Corporation
*/
#ifndef _ABI_GUC_KLVS_ABI_H
#define _ABI_GUC_KLVS_ABI_H
#include <linux/types.h>
#include "abi/guc_scheduler_abi.h"
/**
* DOC: GuC KLV
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31:16 | **KEY** - KLV key identifier |
* | | | - `GuC Self Config KLVs`_ |
* | | | - `GuC Opt In Feature KLVs`_ |
* | | | - `GuC Scheduling Policies KLVs`_ |
* | | | - `GuC VGT Policy KLVs`_ |
* | | | - `GuC VF Configuration KLVs`_ |
* | | | |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | **LEN** - length of VALUE (in 32bit dwords) |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **VALUE** - actual value of the KLV (format depends on KEY) |
* +---+-------+ |
* |...| | |
* +---+-------+ |
* | n | 31:0 | |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_KLV_LEN_MIN 1u
#define GUC_KLV_0_KEY (0xffffu << 16)
#define GUC_KLV_0_LEN (0xffffu << 0)
#define GUC_KLV_n_VALUE (0xffffffffu << 0)
/**
* DOC: GuC Global Config KLVs
*
* `GuC KLV`_ keys available for use with HOST2GUC_SELF_CFG_.
*
* _`GUC_KLV_GLOBAL_CFG_GMD_ID` : 0x3000
* Refers to 32 bit architecture version as reported by the HW IP.
* This key is supported on MTL+ platforms only.
* Requires GuC ABI 1.2+.
*
* _`GUC_KLV_GLOBAL_CFG_GROUP_SCHEDULING_AVAILABLE` : 0x3001
* Tells the driver whether scheduler groups are enabled or not.
* Requires GuC ABI 1.26+
*/
#define GUC_KLV_GLOBAL_CFG_GMD_ID_KEY 0x3000u
#define GUC_KLV_GLOBAL_CFG_GMD_ID_LEN 1u
#define GUC_KLV_GLOBAL_CFG_GROUP_SCHEDULING_AVAILABLE_KEY 0x3001u
#define GUC_KLV_GLOBAL_CFG_GROUP_SCHEDULING_AVAILABLE_LEN 1u
/**
* DOC: GuC Self Config KLVs
*
* `GuC KLV`_ keys available for use with HOST2GUC_SELF_CFG_.
*
* _`GUC_KLV_SELF_CFG_MEMIRQ_STATUS_ADDR` : 0x0900
* Refers to 64 bit Global Gfx address (in bytes) of memory based interrupts
* status vector for use by the GuC.
*
* _`GUC_KLV_SELF_CFG_MEMIRQ_SOURCE_ADDR` : 0x0901
* Refers to 64 bit Global Gfx address (in bytes) of memory based interrupts
* source vector for use by the GuC.
*
* _`GUC_KLV_SELF_CFG_H2G_CTB_ADDR` : 0x0902
* Refers to 64 bit Global Gfx address of H2G `CT Buffer`_.
* Should be above WOPCM address but below APIC base address for native mode.
*
* _`GUC_KLV_SELF_CFG_H2G_CTB_DESCRIPTOR_ADDR : 0x0903
* Refers to 64 bit Global Gfx address of H2G `CTB Descriptor`_.
* Should be above WOPCM address but below APIC base address for native mode.
*
* _`GUC_KLV_SELF_CFG_H2G_CTB_SIZE : 0x0904
* Refers to size of H2G `CT Buffer`_ in bytes.
* Should be a multiple of 4K.
*
* _`GUC_KLV_SELF_CFG_G2H_CTB_ADDR : 0x0905
* Refers to 64 bit Global Gfx address of G2H `CT Buffer`_.
* Should be above WOPCM address but below APIC base address for native mode.
*
* _GUC_KLV_SELF_CFG_G2H_CTB_DESCRIPTOR_ADDR : 0x0906
* Refers to 64 bit Global Gfx address of G2H `CTB Descriptor`_.
* Should be above WOPCM address but below APIC base address for native mode.
*
* _GUC_KLV_SELF_CFG_G2H_CTB_SIZE : 0x0907
* Refers to size of G2H `CT Buffer`_ in bytes.
* Should be a multiple of 4K.
*/
#define GUC_KLV_SELF_CFG_MEMIRQ_STATUS_ADDR_KEY 0x0900
#define GUC_KLV_SELF_CFG_MEMIRQ_STATUS_ADDR_LEN 2u
#define GUC_KLV_SELF_CFG_MEMIRQ_SOURCE_ADDR_KEY 0x0901
#define GUC_KLV_SELF_CFG_MEMIRQ_SOURCE_ADDR_LEN 2u
#define GUC_KLV_SELF_CFG_H2G_CTB_ADDR_KEY 0x0902
#define GUC_KLV_SELF_CFG_H2G_CTB_ADDR_LEN 2u
#define GUC_KLV_SELF_CFG_H2G_CTB_DESCRIPTOR_ADDR_KEY 0x0903
#define GUC_KLV_SELF_CFG_H2G_CTB_DESCRIPTOR_ADDR_LEN 2u
#define GUC_KLV_SELF_CFG_H2G_CTB_SIZE_KEY 0x0904
#define GUC_KLV_SELF_CFG_H2G_CTB_SIZE_LEN 1u
#define GUC_KLV_SELF_CFG_G2H_CTB_ADDR_KEY 0x0905
#define GUC_KLV_SELF_CFG_G2H_CTB_ADDR_LEN 2u
#define GUC_KLV_SELF_CFG_G2H_CTB_DESCRIPTOR_ADDR_KEY 0x0906
#define GUC_KLV_SELF_CFG_G2H_CTB_DESCRIPTOR_ADDR_LEN 2u
#define GUC_KLV_SELF_CFG_G2H_CTB_SIZE_KEY 0x0907
#define GUC_KLV_SELF_CFG_G2H_CTB_SIZE_LEN 1u
/*
* Per context scheduling policy update keys.
*/
enum {
GUC_CONTEXT_POLICIES_KLV_ID_EXECUTION_QUANTUM = 0x2001,
GUC_CONTEXT_POLICIES_KLV_ID_PREEMPTION_TIMEOUT = 0x2002,
GUC_CONTEXT_POLICIES_KLV_ID_SCHEDULING_PRIORITY = 0x2003,
GUC_CONTEXT_POLICIES_KLV_ID_PREEMPT_TO_IDLE_ON_QUANTUM_EXPIRY = 0x2004,
GUC_CONTEXT_POLICIES_KLV_ID_SLPM_GT_FREQUENCY = 0x2005,
GUC_CONTEXT_POLICIES_KLV_NUM_IDS = 5,
};
/**
* DOC: GuC Opt In Feature KLVs
*
* `GuC KLV`_ keys available for use with OPT_IN_FEATURE_KLV
*
* _`GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE` : 0x4001
* Adds an extra dword to the XE_GUC_ACTION_NOTIFY_MEMORY_CAT_ERROR G2H
* containing the type of the CAT error. On HW that does not support
* reporting the CAT error type, the extra dword is set to 0xdeadbeef.
*
* _`GUC_KLV_OPT_IN_FEATURE_DYNAMIC_INHIBIT_CONTEXT_SWITCH` : 0x4003
* This KLV enables the Dynamic Inhibit Context Switch optimization, which
* consists in the GuC setting the CTX_CTRL_INHIBIT_SYN_CTX_SWITCH bit to
* zero in the CTX_CONTEXT_CONTROL register of LRCs that are submitted
* to an oversubscribed engine. This will cause those contexts to be
* switched out immediately if they hit an unsatisfied semaphore wait
* (instead of waiting the full timeslice duration). The bit is instead set
* to one if a single context is queued on the engine, to avoid it being
* switched out if there isn't another context that can run in its place.
*/
#define GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE_KEY 0x4001
#define GUC_KLV_OPT_IN_FEATURE_EXT_CAT_ERR_TYPE_LEN 0u
#define GUC_KLV_OPT_IN_FEATURE_DYNAMIC_INHIBIT_CONTEXT_SWITCH_KEY 0x4003
#define GUC_KLV_OPT_IN_FEATURE_DYNAMIC_INHIBIT_CONTEXT_SWITCH_LEN 0u
/**
* DOC: GuC Scheduling Policies KLVs
*
* `GuC KLV`_ keys available for use with UPDATE_SCHEDULING_POLICIES_KLV.
*
* _`GUC_KLV_SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD` : 0x1001
* Some platforms do not allow concurrent execution of RCS and CCS
* workloads from different address spaces. By default, the GuC prioritizes
* RCS submissions over CCS ones, which can lead to CCS workloads being
* significantly (or completely) starved of execution time. This KLV allows
* the driver to specify a quantum (in ms) and a ratio (percentage value
* between 0 and 100), and the GuC will prioritize the CCS for that
* percentage of each quantum. For example, specifying 100ms and 30% will
* make the GuC prioritize the CCS for 30ms of every 100ms.
* Note that this does not necessarly mean that RCS and CCS engines will
* only be active for their percentage of the quantum, as the restriction
* only kicks in if both classes are fully busy with non-compatible address
* spaces; i.e., if one engine is idle or running the same address space,
* a pending job on the other engine will still be submitted to the HW no
* matter what the ratio is
*/
#define GUC_KLV_SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD_KEY 0x1001
#define GUC_KLV_SCHEDULING_POLICIES_RENDER_COMPUTE_YIELD_LEN 2u
/**
* DOC: GuC VGT Policy KLVs
*
* `GuC KLV`_ keys available for use with PF2GUC_UPDATE_VGT_POLICY.
*
* _`GUC_KLV_VGT_POLICY_SCHED_IF_IDLE` : 0x8001
* [From 70.12.0]
* This config allows to update scheduling priority of PF and all VFs at once.
* Setting this policy to 0 updates all VFs scheduling priorities to LOW, and
* setting this policy to 1 updates all VFs scheduling priorities to NORMAL.
* Those changes will take effect on the next VF-Switch event.
*
* [Before 70.12.0]
* This config sets whether strict scheduling is enabled whereby any VF
* that doesn’t have work to submit is still allocated a fixed execution
* time-slice to ensure active VFs execution is always consistent even
* during other VF reprovisiong / rebooting events. Changing this KLV
* impacts all VFs and takes effect on the next VF-Switch event.
*
* :0: don't schedule idle (default)
* :1: schedule if idle
*
* _`GUC_KLV_VGT_POLICY_ADVERSE_SAMPLE_PERIOD` : 0x8002
* This config sets the sample period for tracking adverse event counters.
* A sample period is the period in millisecs during which events are counted.
* This is applicable for all the VFs.
*
* :0: adverse events are not counted (default)
* :n: sample period in milliseconds
*
* _`GUC_KLV_VGT_POLICY_ENGINE_GROUP_CONFIG` : 0x8004
* This config allows the PF to split the engines across scheduling groups.
* Each group is independently timesliced across VFs, allowing different
* VFs to be active on the HW at the same time. When enabling this feature,
* all engines must be assigned to a group (and only one group), or they
* will be excluded from scheduling after this KLV is sent. To enable
* the groups, the driver must provide a masks array with
* GUC_MAX_ENGINE_CLASSES entries for each group, with each mask indicating
* which logical instances of that class belong to the group. Therefore,
* the length of this KLV when enabling groups is
* num_groups * GUC_MAX_ENGINE_CLASSES. To disable the groups, the driver
* must send the KLV without any payload (i.e. len = 0). The maximum
* number of groups is 8.
*
* _`GUC_KLV_VGT_POLICY_RESET_AFTER_VF_SWITCH` : 0x8D00
* This enum is to reset utilized HW engine after VF Switch (i.e to clean
* up Stale HW register left behind by previous VF)
*
* :0: don't reset (default)
* :1: reset
*/
#define GUC_KLV_VGT_POLICY_SCHED_IF_IDLE_KEY 0x8001
#define GUC_KLV_VGT_POLICY_SCHED_IF_IDLE_LEN 1u
#define GUC_KLV_VGT_POLICY_ADVERSE_SAMPLE_PERIOD_KEY 0x8002
#define GUC_KLV_VGT_POLICY_ADVERSE_SAMPLE_PERIOD_LEN 1u
#define GUC_KLV_VGT_POLICY_ENGINE_GROUP_CONFIG_KEY 0x8004
#define GUC_KLV_VGT_POLICY_ENGINE_GROUP_MAX_COUNT GUC_MAX_SCHED_GROUPS
#define GUC_KLV_VGT_POLICY_ENGINE_GROUP_CONFIG_MIN_LEN 0
#define GUC_KLV_VGT_POLICY_ENGINE_GROUP_CONFIG_MAX_LEN \
(GUC_KLV_VGT_POLICY_ENGINE_GROUP_MAX_COUNT * GUC_MAX_ENGINE_CLASSES)
#define GUC_KLV_VGT_POLICY_RESET_AFTER_VF_SWITCH_KEY 0x8D00
#define GUC_KLV_VGT_POLICY_RESET_AFTER_VF_SWITCH_LEN 1u
/**
* DOC: GuC VF Configuration KLVs
*
* `GuC KLV`_ keys available for use with PF2GUC_UPDATE_VF_CFG.
*
* _`GUC_KLV_VF_CFG_GGTT_START` : 0x0001
* A 4K aligned start GTT address/offset assigned to VF.
* Value is 64 bits.
*
* _`GUC_KLV_VF_CFG_GGTT_SIZE` : 0x0002
* A 4K aligned size of GGTT assigned to VF.
* Value is 64 bits.
*
* _`GUC_KLV_VF_CFG_LMEM_SIZE` : 0x0003
* A 2M aligned size of local memory assigned to VF.
* Value is 64 bits.
*
* _`GUC_KLV_VF_CFG_NUM_CONTEXTS` : 0x0004
* Refers to the number of contexts allocated to this VF.
*
* :0: no contexts (default)
* :1-65535: number of contexts (Gen12)
*
* _`GUC_KLV_VF_CFG_TILE_MASK` : 0x0005
* For multi-tiled products, this field contains the bitwise-OR of tiles
* assigned to the VF. Bit-0-set means VF has access to Tile-0,
* Bit-31-set means VF has access to Tile-31, and etc.
* At least one tile will always be allocated.
* If all bits are zero, VF KMD should treat this as a fatal error.
* For, single-tile products this KLV config is ignored.
*
* _`GUC_KLV_VF_CFG_NUM_DOORBELLS` : 0x0006
* Refers to the number of doorbells allocated to this VF.
*
* :0: no doorbells (default)
* :1-255: number of doorbells (Gen12)
*
* _`GUC_KLV_VF_CFG_EXEC_QUANTUM` : 0x8A01
* This config sets the VFs-execution-quantum in milliseconds.
* GUC will attempt to obey the maximum values as much as HW is capable
* of and this will never be perfectly-exact (accumulated nano-second
* granularity) since the GPUs clock time runs off a different crystal
* from the CPUs clock. Changing this KLV on a VF that is currently
* running a context won't take effect until a new context is scheduled in.
* That said, when the PF is changing this value from 0x0 to
* a non-zero value, it might never take effect if the VF is running an
* infinitely long compute or shader kernel. In such a scenario, the
* PF would need to trigger a VM PAUSE and then change the KLV to force
* it to take effect. Such cases might typically happen on a 1PF+1VF
* Virtualization config enabled for heavier workloads like AI/ML.
*
* If scheduling groups are supported, the provided value is applied to all
* groups (even if they've not yet been enabled). Support for this feature
* is available from GuC 70.53.0.
*
* The max value for this KLV is 100 seconds, anything exceeding that
* will be clamped to the max.
*
* :0: infinite exec quantum (default)
* :100000: maximum exec quantum (100000ms == 100s)
*
* _`GUC_KLV_VF_CFG_PREEMPT_TIMEOUT` : 0x8A02
* This config sets the VF-preemption-timeout in microseconds.
* GUC will attempt to obey the minimum and maximum values as much as
* HW is capable and this will never be perfectly-exact (accumulated
* nano-second granularity) since the GPUs clock time runs off a
* different crystal from the CPUs clock. Changing this KLV on a VF
* that is currently running a context won't take effect until a new
* context is scheduled in.
* That said, when the PF is changing this value from 0x0 to
* a non-zero value, it might never take effect if the VF is running an
* infinitely long compute or shader kernel.
* In this case, the PF would need to trigger a VM PAUSE and then change
* the KLV to force it to take effect. Such cases might typically happen
* on a 1PF+1VF Virtualization config enabled for heavier workloads like
* AI/ML.
*
* If scheduling groups are supported, the provided value is applied to all
* groups (even if they've not yet been enabled). Support for this feature
* is available from GuC 70.53.0.
*
* The max value for this KLV is 100 seconds, anything exceeding that
* will be clamped to the max.
*
* :0: no preemption timeout (default)
* :100000000: maximum preemption timeout (100000000us == 100s)
*
* _`GUC_KLV_VF_CFG_THRESHOLD_CAT_ERR` : 0x8A03
* This config sets threshold for CAT errors caused by the VF.
*
* :0: adverse events or error will not be reported (default)
* :n: event occurrence count per sampling interval
*
* _`GUC_KLV_VF_CFG_THRESHOLD_ENGINE_RESET` : 0x8A04
* This config sets threshold for engine reset caused by the VF.
*
* :0: adverse events or error will not be reported (default)
* :n: event occurrence count per sampling interval
*
* _`GUC_KLV_VF_CFG_THRESHOLD_PAGE_FAULT` : 0x8A05
* This config sets threshold for page fault errors caused by the VF.
*
* :0: adverse events or error will not be reported (default)
* :n: event occurrence count per sampling interval
*
* _`GUC_KLV_VF_CFG_THRESHOLD_H2G_STORM` : 0x8A06
* This config sets threshold for H2G interrupts triggered by the VF.
*
* :0: adverse events or error will not be reported (default)
* :n: time (us) per sampling interval
*
* _`GUC_KLV_VF_CFG_THRESHOLD_IRQ_STORM` : 0x8A07
* This config sets threshold for GT interrupts triggered by the VF's
* workloads.
*
* :0: adverse events or error will not be reported (default)
* :n: time (us) per sampling interval
*
* _`GUC_KLV_VF_CFG_THRESHOLD_DOORBELL_STORM` : 0x8A08
* This config sets threshold for doorbell's ring triggered by the VF.
*
* :0: adverse events or error will not be reported (default)
* :n: time (us) per sampling interval
*
* _`GUC_KLV_VF_CFG_BEGIN_DOORBELL_ID` : 0x8A0A
* Refers to the start index of doorbell assigned to this VF.
*
* :0: (default)
* :1-255: number of doorbells (Gen12)
*
* _`GUC_KLV_VF_CFG_BEGIN_CONTEXT_ID` : 0x8A0B
* Refers to the start index in context array allocated to this VF’s use.
*
* :0: (default)
* :1-65535: number of contexts (Gen12)
*
* _`GUC_KLV_VF_CFG_SCHED_PRIORITY` : 0x8A0C
* This config controls VF’s scheduling priority.
*
* :0: LOW = schedule VF only if it has active work (default)
* :1: NORMAL = schedule VF always, irrespective of whether it has work or not
* :2: HIGH = schedule VF in the next time-slice after current active
* time-slice completes if it has active work
*
* _`GUC_KLV_VF_CFG_THRESHOLD_MULTI_LRC_COUNT` : 0x8A0D
* Given that multi-LRC contexts are incompatible with SRIOV scheduler
* groups and cause the latter to be turned off when registered with the
* GuC, this config allows the PF to set a threshold for multi-LRC context
* registrations by VFs to monitor their behavior.
*
* _`GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM' : 0x8A0E
* This config sets the VFs-execution-quantum for each scheduling group in
* milliseconds. The driver must provide an array of values, with each of
* them matching the respective group index (first value goes to group 0,
* second to group 1, etc). The setting of group values follows the same
* behavior and rules as setting via GUC_KLV_VF_CFG_EXEC_QUANTUM. Note that
* the GuC always sets the EQ for all groups (even the non-enabled ones),
* so if we provide fewer values than the max the GuC will use 0 for the
* remaining groups. This KLV is available starting from GuC 70.53.0.
*
* _`GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT' : 0x8A0F
* This config sets the VFs-preemption-timeout for each scheduling group in
* microseconds. The driver must provide an array of values, with each of
* them matching the respective group index (first value goes to group 0,
* second to group 1, etc). The setting of group values follows the same
* behavior and rules as setting via GUC_KLV_VF_CFG_PREEMPT_TIMEOUT. Note
* that the GuC always sets the EQ for all groups (even the non-enabled
* ones), so if we provide fewer values than the max the GuC will use 0 for
* the remaining groups. This KLV is available starting from GuC 70.53.0.
*/
#define GUC_KLV_VF_CFG_GGTT_START_KEY 0x0001
#define GUC_KLV_VF_CFG_GGTT_START_LEN 2u
#define GUC_KLV_VF_CFG_GGTT_SIZE_KEY 0x0002
#define GUC_KLV_VF_CFG_GGTT_SIZE_LEN 2u
#define GUC_KLV_VF_CFG_LMEM_SIZE_KEY 0x0003
#define GUC_KLV_VF_CFG_LMEM_SIZE_LEN 2u
#define GUC_KLV_VF_CFG_NUM_CONTEXTS_KEY 0x0004
#define GUC_KLV_VF_CFG_NUM_CONTEXTS_LEN 1u
#define GUC_KLV_VF_CFG_TILE_MASK_KEY 0x0005
#define GUC_KLV_VF_CFG_TILE_MASK_LEN 1u
#define GUC_KLV_VF_CFG_NUM_DOORBELLS_KEY 0x0006
#define GUC_KLV_VF_CFG_NUM_DOORBELLS_LEN 1u
#define GUC_KLV_VF_CFG_EXEC_QUANTUM_KEY 0x8a01
#define GUC_KLV_VF_CFG_EXEC_QUANTUM_LEN 1u
#define GUC_KLV_VF_CFG_EXEC_QUANTUM_MAX_VALUE 100000u
#define GUC_KLV_VF_CFG_PREEMPT_TIMEOUT_KEY 0x8a02
#define GUC_KLV_VF_CFG_PREEMPT_TIMEOUT_LEN 1u
#define GUC_KLV_VF_CFG_PREEMPT_TIMEOUT_MAX_VALUE 100000000u
#define GUC_KLV_VF_CFG_THRESHOLD_CAT_ERR_KEY 0x8a03
#define GUC_KLV_VF_CFG_THRESHOLD_CAT_ERR_LEN 1u
#define GUC_KLV_VF_CFG_THRESHOLD_ENGINE_RESET_KEY 0x8a04
#define GUC_KLV_VF_CFG_THRESHOLD_ENGINE_RESET_LEN 1u
#define GUC_KLV_VF_CFG_THRESHOLD_PAGE_FAULT_KEY 0x8a05
#define GUC_KLV_VF_CFG_THRESHOLD_PAGE_FAULT_LEN 1u
#define GUC_KLV_VF_CFG_THRESHOLD_H2G_STORM_KEY 0x8a06
#define GUC_KLV_VF_CFG_THRESHOLD_H2G_STORM_LEN 1u
#define GUC_KLV_VF_CFG_THRESHOLD_IRQ_STORM_KEY 0x8a07
#define GUC_KLV_VF_CFG_THRESHOLD_IRQ_STORM_LEN 1u
#define GUC_KLV_VF_CFG_THRESHOLD_DOORBELL_STORM_KEY 0x8a08
#define GUC_KLV_VF_CFG_THRESHOLD_DOORBELL_STORM_LEN 1u
#define GUC_KLV_VF_CFG_BEGIN_DOORBELL_ID_KEY 0x8a0a
#define GUC_KLV_VF_CFG_BEGIN_DOORBELL_ID_LEN 1u
#define GUC_KLV_VF_CFG_BEGIN_CONTEXT_ID_KEY 0x8a0b
#define GUC_KLV_VF_CFG_BEGIN_CONTEXT_ID_LEN 1u
#define GUC_KLV_VF_CFG_SCHED_PRIORITY_KEY 0x8a0c
#define GUC_KLV_VF_CFG_SCHED_PRIORITY_LEN 1u
#define GUC_SCHED_PRIORITY_LOW 0u
#define GUC_SCHED_PRIORITY_NORMAL 1u
#define GUC_SCHED_PRIORITY_HIGH 2u
#define GUC_KLV_VF_CFG_THRESHOLD_MULTI_LRC_COUNT_KEY 0x8a0d
#define GUC_KLV_VF_CFG_THRESHOLD_MULTI_LRC_COUNT_LEN 1u
#define GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM_KEY 0x8a0e
#define GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM_MIN_LEN 1u
#define GUC_KLV_VF_CFG_ENGINE_GROUP_EXEC_QUANTUM_MAX_LEN GUC_MAX_SCHED_GROUPS
#define GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_KEY 0x8a0f
#define GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_MIN_LEN 1u
#define GUC_KLV_VF_CFG_ENGINE_GROUP_PREEMPT_TIMEOUT_MAX_LEN GUC_MAX_SCHED_GROUPS
/*
* Workaround keys:
*/
enum xe_guc_klv_ids {
GUC_WORKAROUND_KLV_BLOCK_INTERRUPTS_WHEN_MGSR_BLOCKED = 0x9002,
GUC_WORKAROUND_KLV_DISABLE_PSMI_INTERRUPTS_AT_C6_ENTRY_RESTORE_AT_EXIT = 0x9004,
GUC_WORKAROUND_KLV_ID_GAM_PFQ_SHADOW_TAIL_POLLING = 0x9005,
GUC_WORKAROUND_KLV_ID_DISABLE_MTP_DURING_ASYNC_COMPUTE = 0x9007,
GUC_WA_KLV_NP_RD_WRITE_TO_CLEAR_RCSM_AT_CGP_LATE_RESTORE = 0x9008,
GUC_WORKAROUND_KLV_ID_BACK_TO_BACK_RCS_ENGINE_RESET = 0x9009,
GUC_WA_KLV_WAKE_POWER_DOMAINS_FOR_OUTBOUND_MMIO = 0x900a,
GUC_WA_KLV_RESET_BB_STACK_PTR_ON_VF_SWITCH = 0x900b,
GUC_WA_KLV_RESTORE_UNSAVED_MEDIA_CONTROL_REG = 0x900c,
GUC_WA_KLV_CLR_CS_INDIRECT_RING_STATE_IF_IDLE_AT_CTX_REG = 0x900e,
};
#endif
@@ -0,0 +1,170 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2025 Intel Corporation
*/
#ifndef _ABI_GUC_LFD_ABI_H_
#define _ABI_GUC_LFD_ABI_H_
#include <linux/types.h>
#include "guc_lic_abi.h"
/* The current major version of GuC-Log-File format. */
#define GUC_LFD_FORMAT_VERSION_MAJOR 0x0001
/* The current minor version of GuC-Log-File format. */
#define GUC_LFD_FORMAT_VERSION_MINOR 0x0000
/** enum guc_lfd_type - Log format descriptor type */
enum guc_lfd_type {
/**
* @GUC_LFD_TYPE_FW_REQUIRED_RANGE_START: Start of range for
* required LFDs from GuC
* @GUC_LFD_TYPE_FW_VERSION: GuC Firmware Version structure.
* @GUC_LFD_TYPE_GUC_DEVICE_ID: GuC microcontroller device ID.
* @GUC_LFD_TYPE_TSC_FREQUENCY: Frequency of GuC timestamps.
* @GUC_LFD_TYPE_GMD_ID: HW GMD ID.
* @GUC_LFD_TYPE_BUILD_PLATFORM_ID: GuC build platform ID.
* @GUC_LFD_TYPE_FW_REQUIRED_RANGE_END: End of range for
* required LFDs from GuC
*/
GUC_LFD_TYPE_FW_REQUIRED_RANGE_START = 0x1,
GUC_LFD_TYPE_FW_VERSION = 0x1,
GUC_LFD_TYPE_GUC_DEVICE_ID = 0x2,
GUC_LFD_TYPE_TSC_FREQUENCY = 0x3,
GUC_LFD_TYPE_GMD_ID = 0x4,
GUC_LFD_TYPE_BUILD_PLATFORM_ID = 0x5,
GUC_LFD_TYPE_FW_REQUIRED_RANGE_END = 0x1FFF,
/**
* @GUC_LFD_TYPE_FW_OPTIONAL_RANGE_START: Start of range for
* optional LFDs from GuC
* @GUC_LFD_TYPE_LOG_EVENTS_BUFFER: Log-event-entries buffer.
* @GUC_LFD_TYPE_FW_CRASH_DUMP: GuC generated crash-dump blob.
* @GUC_LFD_TYPE_FW_OPTIONAL_RANGE_END: End of range for
* optional LFDs from GuC
*/
GUC_LFD_TYPE_FW_OPTIONAL_RANGE_START = 0x2000,
GUC_LFD_TYPE_LOG_EVENTS_BUFFER = 0x2000,
GUC_LFD_TYPE_FW_CRASH_DUMP = 0x2001,
GUC_LFD_TYPE_FW_OPTIONAL_RANGE_END = 0x3FFF,
/**
* @GUC_LFD_TYPE_KMD_REQUIRED_RANGE_START: Start of range for
* required KMD LFDs
* @GUC_LFD_TYPE_OS_ID: An identifier for the OS.
* @GUC_LFD_TYPE_KMD_REQUIRED_RANGE_END: End of this range for
* required KMD LFDs
*/
GUC_LFD_TYPE_KMD_REQUIRED_RANGE_START = 0x4000,
GUC_LFD_TYPE_OS_ID = 0x4000,
GUC_LFD_TYPE_KMD_REQUIRED_RANGE_END = 0x5FFF,
/**
* @GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_START: Start of range for
* optional KMD LFDs
* @GUC_LFD_TYPE_BINARY_SCHEMA_FORMAT: Binary representation of
* GuC log-events schema.
* @GUC_LFD_TYPE_HOST_COMMENT: ASCII string containing comments
* from the host/KMD.
* @GUC_LFD_TYPE_TIMESTAMP_ANCHOR: A timestamp anchor, to convert
* between host and GuC timestamp.
* @GUC_LFD_TYPE_TIMESTAMP_ANCHOR_CONFIG: Timestamp anchor
* configuration, definition of timestamp frequency and bit width.
* @GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_END: End of this range for
* optional KMD LFDs
*/
GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_START = 0x6000,
GUC_LFD_TYPE_BINARY_SCHEMA_FORMAT = 0x6000,
GUC_LFD_TYPE_HOST_COMMENT = 0x6001,
GUC_LFD_TYPE_TIMESTAMP_ANCHOR = 0x6002,
GUC_LFD_TYPE_TIMESTAMP_ANCHOR_CONFIG = 0x6003,
GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_END = 0x7FFF,
/*
* @GUC_LFD_TYPE_RESERVED_RANGE_START: Start of reserved range
* @GUC_LFD_TYPE_RESERVED_RANGE_END: End of reserved range
*/
GUC_LFD_TYPE_RESERVED_RANGE_START = 0x8000,
GUC_LFD_TYPE_RESERVED_RANGE_END = 0xFFFF,
};
/** enum guc_lfd_os_type - OS Type LFD-ID */
enum guc_lfd_os_type {
/** @GUC_LFD_OS_TYPE_OSID_WIN: Windows OS */
GUC_LFD_OS_TYPE_OSID_WIN = 0x1,
/** @GUC_LFD_OS_TYPE_OSID_LIN: Linux OS */
GUC_LFD_OS_TYPE_OSID_LIN = 0x2,
/** @GUC_LFD_OS_TYPE_OSID_VMW: VMWare OS */
GUC_LFD_OS_TYPE_OSID_VMW = 0x3,
/** @GUC_LFD_OS_TYPE_OSID_OTHER: Other */
GUC_LFD_OS_TYPE_OSID_OTHER = 0x4,
};
/** struct guc_lfd_data - A generic header structure for all LFD blocks */
struct guc_lfd_data {
/** @header: A 32 bits dword, contains multiple bit fields */
u32 header;
/* LFD type. See guc_lfd_type */
#define GUC_LFD_DATA_HEADER_MASK_TYPE GENMASK(31, 16)
#define GUC_LFD_DATA_HEADER_MASK_MAGIC GENMASK(15, 0)
/** @data_count: Number of dwords the `data` field contains. */
u32 data_count;
/** @data: Data defined by GUC_LFD_DATA_HEADER_MASK_TYPE */
u32 data[] __counted_by(data_count);
} __packed;
/**
* struct guc_lfd_data_log_events_buf - GuC Log Events Buffer.
* This is optional fw LFD data
*/
struct guc_lfd_data_log_events_buf {
/**
* @log_events_format_version: version of GuC log format of buffer
*/
u32 log_events_format_version;
/**
* @log_event: The log event data.
* Size in dwords is LFD block size - 1.
*/
u32 log_event[];
} __packed;
/** struct guc_lfd_data_os_info - OS Version Information. */
struct guc_lfd_data_os_info {
/**
* @os_id: enum values to identify the OS brand.
* See guc_lfd_os_type for the range of types
*/
u32 os_id;
/**
* @build_version: ASCII string containing OS build version
* information based on os_id. String is padded with null
* characters to ensure its DWORD aligned.
* Size in dwords is LFD block size - 1.
*/
char build_version[];
} __packed;
/**
* struct guc_lfd_file_header - Header of GuC Log Streaming-LFD-File Format.
* This structure encapsulates the layout of the guc-log-file format
*/
struct guc_lfd_file_header {
/**
* @magic: A magic number set by producer of a GuC log file to
* identify that file is a valid guc-log-file containing a stream
* of LFDs.
*/
u64 magic;
/** @version: Version of this file format layout */
u32 version;
#define GUC_LFD_FILE_HEADER_VERSION_MASK_MAJOR GENMASK(31, 16)
#define GUC_LFD_FILE_HEADER_VERSION_MASK_MINOR GENMASK(15, 0)
/** @stream: A stream of one or more guc_lfd_data LFD blocks */
u32 stream[];
} __packed;
#endif
@@ -0,0 +1,77 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2025 Intel Corporation
*/
#ifndef _ABI_GUC_LIC_ABI_H_
#define _ABI_GUC_LIC_ABI_H_
#include <linux/types.h>
/**
* enum guc_lic_type - Log Init Config KLV IDs.
*/
enum guc_lic_type {
/**
* @GUC_LIC_TYPE_GUC_SW_VERSION: GuC firmware version. Value
* is a 32 bit number represented by guc_sw_version.
*/
GUC_LIC_TYPE_GUC_SW_VERSION = 0x1,
/**
* @GUC_LIC_TYPE_GUC_DEVICE_ID: GuC device id. Value is a 32
* bit.
*/
GUC_LIC_TYPE_GUC_DEVICE_ID = 0x2,
/**
* @GUC_LIC_TYPE_TSC_FREQUENCY: GuC timestamp counter
* frequency. Value is a 32 bit number representing frequency in
* kHz. This timestamp is utilized in log entries, timer and
* for engine utilization tracking.
*/
GUC_LIC_TYPE_TSC_FREQUENCY = 0x3,
/**
* @GUC_LIC_TYPE_GMD_ID: HW GMD ID. Value is a 32 bit number
* representing graphics, media and display HW architecture IDs.
*/
GUC_LIC_TYPE_GMD_ID = 0x4,
/**
* @GUC_LIC_TYPE_BUILD_PLATFORM_ID: GuC build platform ID.
* Value is 32 bits.
*/
GUC_LIC_TYPE_BUILD_PLATFORM_ID = 0x5,
};
/**
* struct guc_lic - GuC LIC (Log-Init-Config) structure.
*
* This is populated by the GUC at log init time and is located in the log
* buffer memory allocation.
*/
struct guc_lic {
/**
* @magic: A magic number set by GuC to identify that this
* structure contains valid information: magic = GUC_LIC_MAGIC.
*/
u32 magic;
#define GUC_LIC_MAGIC 0x8086900D
/**
* @version: The version of the this structure.
* Major and minor version number are represented as bit fields.
*/
u32 version;
#define GUC_LIC_VERSION_MASK_MAJOR GENMASK(31, 16)
#define GUC_LIC_VERSION_MASK_MINOR GENMASK(15, 0)
#define GUC_LIC_VERSION_MAJOR 1u
#define GUC_LIC_VERSION_MINOR 0u
/** @data_count: Number of dwords the `data` array contains. */
u32 data_count;
/**
* @data: Array of dwords representing a list of LIC KLVs of
* type guc_klv_generic with keys represented by guc_lic_type
*/
u32 data[] __counted_by(data_count);
} __packed;
#endif
@@ -0,0 +1,109 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef _ABI_GUC_LOG_ABI_H
#define _ABI_GUC_LOG_ABI_H
#include <linux/types.h>
/**
* DOC: GuC Log buffer Layout
*
* The in-memory log buffer layout is as follows::
*
* +===============================+ 0000h
* | Crash dump state header | ^
* +-------------------------------+ 32B |
* | Debug state header | |
* +-------------------------------+ 64B 4KB
* | Capture state header | |
* +-------------------------------+ 96B |
* | | v
* +===============================+ <--- EVENT_DATA_OFFSET
* | Event logs(raw data) | ^
* | | |
* | | EVENT_DATA_BUFFER_SIZE
* | | |
* | | v
* +===============================+ <--- CRASH_DUMP_OFFSET
* | Crash Dump(raw data) | ^
* | | |
* | | CRASH_DUMP_BUFFER_SIZE
* | | |
* | | v
* +===============================+ <--- STATE_CAPTURE_OFFSET
* | Error state capture(raw data) | ^
* | | |
* | | STATE_CAPTURE_BUFFER_SIZE
* | | |
* | | v
* +===============================+ Total: GUC_LOG_SIZE
*/
/* GuC logging buffer types */
enum guc_log_type {
GUC_LOG_TYPE_EVENT_DATA,
GUC_LOG_TYPE_CRASH_DUMP,
GUC_LOG_TYPE_STATE_CAPTURE,
};
#define GUC_LOG_BUFFER_TYPE_MAX 3
/**
* struct guc_log_buffer_state - GuC log buffer state
*
* Below state structure is used for coordination of retrieval of GuC firmware
* logs. Separate state is maintained for each log buffer type.
* read_ptr points to the location where Xe read last in log buffer and
* is read only for GuC firmware. write_ptr is incremented by GuC with number
* of bytes written for each log entry and is read only for Xe.
* When any type of log buffer becomes half full, GuC sends a flush interrupt.
* GuC firmware expects that while it is writing to 2nd half of the buffer,
* first half would get consumed by Host and then get a flush completed
* acknowledgment from Host, so that it does not end up doing any overwrite
* causing loss of logs. So when buffer gets half filled & Xe has requested
* for interrupt, GuC will set flush_to_file field, set the sampled_write_ptr
* to the value of write_ptr and raise the interrupt.
* On receiving the interrupt Xe should read the buffer, clear flush_to_file
* field and also update read_ptr with the value of sample_write_ptr, before
* sending an acknowledgment to GuC. marker & version fields are for internal
* usage of GuC and opaque to Xe. buffer_full_cnt field is incremented every
* time GuC detects the log buffer overflow.
*/
struct guc_log_buffer_state {
/** @marker: buffer state start marker */
u32 marker[2];
/** @read_ptr: the last byte offset that was read by KMD previously */
u32 read_ptr;
/**
* @write_ptr: the next byte offset location that will be written by
* GuC
*/
u32 write_ptr;
/** @size: Log buffer size */
u32 size;
/**
* @sampled_write_ptr: Log buffer write pointer
* This is written by GuC to the byte offset of the next free entry in
* the buffer on log buffer half full or state capture notification
*/
u32 sampled_write_ptr;
/**
* @wrap_offset: wraparound offset
* This is the byte offset of location 1 byte after last valid guc log
* event entry written by Guc firmware before there was a wraparound.
* This field is updated by guc firmware and should be used by Host
* when copying buffer contents to file.
*/
u32 wrap_offset;
/** @flags: Flush to file flag and buffer full count */
u32 flags;
#define GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE GENMASK(0, 0)
#define GUC_LOG_BUFFER_STATE_BUFFER_FULL_CNT GENMASK(4, 1)
/** @version: The Guc-Log-Entry format version */
u32 version;
} __packed;
#endif
@@ -0,0 +1,251 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2014-2021 Intel Corporation
*/
#ifndef _ABI_GUC_MESSAGES_ABI_H
#define _ABI_GUC_MESSAGES_ABI_H
/**
* DOC: HXG Message
*
* All messages exchanged with GuC are defined using 32 bit dwords.
* First dword is treated as a message header. Remaining dwords are optional.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | | | |
* | 0 | 31 | **ORIGIN** - originator of the message |
* | | | - _`GUC_HXG_ORIGIN_HOST` = 0 |
* | | | - _`GUC_HXG_ORIGIN_GUC` = 1 |
* | | | |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | **TYPE** - message type |
* | | | - _`GUC_HXG_TYPE_REQUEST` = 0 |
* | | | - _`GUC_HXG_TYPE_EVENT` = 1 |
* | | | - _`GUC_HXG_TYPE_FAST_REQUEST` = 2 |
* | | | - _`GUC_HXG_TYPE_NO_RESPONSE_BUSY` = 3 |
* | | | - _`GUC_HXG_TYPE_NO_RESPONSE_RETRY` = 5 |
* | | | - _`GUC_HXG_TYPE_RESPONSE_FAILURE` = 6 |
* | | | - _`GUC_HXG_TYPE_RESPONSE_SUCCESS` = 7 |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | **AUX** - auxiliary data (depends on TYPE) |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | |
* +---+-------+ |
* |...| | **PAYLOAD** - optional payload (depends on TYPE) |
* +---+-------+ |
* | n | 31:0 | |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_HXG_MSG_MIN_LEN 1u
#define GUC_HXG_MSG_0_ORIGIN (0x1u << 31)
#define GUC_HXG_ORIGIN_HOST 0u
#define GUC_HXG_ORIGIN_GUC 1u
#define GUC_HXG_MSG_0_TYPE (0x7u << 28)
#define GUC_HXG_TYPE_REQUEST 0u
#define GUC_HXG_TYPE_EVENT 1u
#define GUC_HXG_TYPE_FAST_REQUEST 2u
#define GUC_HXG_TYPE_NO_RESPONSE_BUSY 3u
#define GUC_HXG_TYPE_NO_RESPONSE_RETRY 5u
#define GUC_HXG_TYPE_RESPONSE_FAILURE 6u
#define GUC_HXG_TYPE_RESPONSE_SUCCESS 7u
#define GUC_HXG_MSG_0_AUX (0xfffffffu << 0)
#define GUC_HXG_MSG_n_PAYLOAD (0xffffffffu << 0)
/**
* DOC: HXG Request
*
* The `HXG Request`_ message should be used to initiate synchronous activity
* for which confirmation or return data is expected.
*
* The recipient of this message shall use `HXG Response`_, `HXG Failure`_
* or `HXG Retry`_ message as a definite reply, and may use `HXG Busy`_
* message as a intermediate reply.
*
* Format of @DATA0 and all @DATAn fields depends on the @ACTION code.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | **DATA0** - request data (depends on ACTION) |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | **ACTION** - requested action code |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | |
* +---+-------+ |
* |...| | **DATAn** - optional data (depends on ACTION) |
* +---+-------+ |
* | n | 31:0 | |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_HXG_REQUEST_MSG_MIN_LEN GUC_HXG_MSG_MIN_LEN
#define GUC_HXG_REQUEST_MSG_0_DATA0 (0xfffu << 16)
#define GUC_HXG_REQUEST_MSG_0_ACTION (0xffffu << 0)
#define GUC_HXG_REQUEST_MSG_n_DATAn GUC_HXG_MSG_n_PAYLOAD
/**
* DOC: HXG Fast Request
*
* The `HXG Request`_ message should be used to initiate asynchronous activity
* for which confirmation or return data is not expected.
*
* If confirmation is required then `HXG Request`_ shall be used instead.
*
* The recipient of this message may only use `HXG Failure`_ message if it was
* unable to accept this request (like invalid data).
*
* Format of `HXG Fast Request`_ message is same as `HXG Request`_ except @TYPE.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN - see `HXG Message`_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = `GUC_HXG_TYPE_FAST_REQUEST`_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 - see `HXG Request`_ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION - see `HXG Request`_ |
* +---+-------+--------------------------------------------------------------+
* |...| | DATAn - see `HXG Request`_ |
* +---+-------+--------------------------------------------------------------+
*/
/**
* DOC: HXG Event
*
* The `HXG Event`_ message should be used to initiate asynchronous activity
* that does not involves immediate confirmation nor data.
*
* Format of @DATA0 and all @DATAn fields depends on the @ACTION code.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_EVENT_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | **DATA0** - event data (depends on ACTION) |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | **ACTION** - event action code |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | |
* +---+-------+ |
* |...| | **DATAn** - optional event data (depends on ACTION) |
* +---+-------+ |
* | n | 31:0 | |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_HXG_EVENT_MSG_MIN_LEN GUC_HXG_MSG_MIN_LEN
#define GUC_HXG_EVENT_MSG_0_DATA0 (0xfffu << 16)
#define GUC_HXG_EVENT_MSG_0_ACTION (0xffffu << 0)
#define GUC_HXG_EVENT_MSG_n_DATAn GUC_HXG_MSG_n_PAYLOAD
/**
* DOC: HXG Busy
*
* The `HXG Busy`_ message may be used to acknowledge reception of the `HXG Request`_
* message if the recipient expects that it processing will be longer than default
* timeout.
*
* The @COUNTER field may be used as a progress indicator.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_NO_RESPONSE_BUSY_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | **COUNTER** - progress indicator |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_HXG_BUSY_MSG_LEN GUC_HXG_MSG_MIN_LEN
#define GUC_HXG_BUSY_MSG_0_COUNTER GUC_HXG_MSG_0_AUX
/**
* DOC: HXG Retry
*
* The `HXG Retry`_ message should be used by recipient to indicate that the
* `HXG Request`_ message was dropped and it should be resent again.
*
* The @REASON field may be used to provide additional information.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_NO_RESPONSE_RETRY_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | **REASON** - reason for retry |
* | | | - _`GUC_HXG_RETRY_REASON_UNSPECIFIED` = 0 |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_HXG_RETRY_MSG_LEN GUC_HXG_MSG_MIN_LEN
#define GUC_HXG_RETRY_MSG_0_REASON GUC_HXG_MSG_0_AUX
#define GUC_HXG_RETRY_REASON_UNSPECIFIED 0u
/**
* DOC: HXG Failure
*
* The `HXG Failure`_ message shall be used as a reply to the `HXG Request`_
* message that could not be processed due to an error.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_FAILURE_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | **HINT** - additional error hint |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | **ERROR** - error/result code |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_HXG_FAILURE_MSG_LEN GUC_HXG_MSG_MIN_LEN
#define GUC_HXG_FAILURE_MSG_0_HINT (0xfffu << 16)
#define GUC_HXG_FAILURE_MSG_0_ERROR (0xffffu << 0)
/**
* DOC: HXG Response
*
* The `HXG Response`_ message shall be used as a reply to the `HXG Request`_
* message that was successfully processed without an error.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | **DATA0** - data (depends on ACTION from `HXG Request`_) |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | |
* +---+-------+ |
* |...| | **DATAn** - data (depends on ACTION from `HXG Request`_) |
* +---+-------+ |
* | n | 31:0 | |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_HXG_RESPONSE_MSG_MIN_LEN GUC_HXG_MSG_MIN_LEN
#define GUC_HXG_RESPONSE_MSG_0_DATA0 GUC_HXG_MSG_0_AUX
#define GUC_HXG_RESPONSE_MSG_n_DATAn GUC_HXG_MSG_n_PAYLOAD
#endif
@@ -0,0 +1,247 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023-2024 Intel Corporation
*/
#ifndef _ABI_GUC_RELAY_ACTIONS_ABI_H_
#define _ABI_GUC_RELAY_ACTIONS_ABI_H_
#include "abi/guc_relay_communication_abi.h"
/**
* DOC: GuC Relay VF/PF ABI Version
*
* The _`GUC_RELAY_VERSION_BASE` defines minimum VF/PF ABI version that
* drivers must support. Currently this is version 1.0.
*
* The _`GUC_RELAY_VERSION_LATEST` defines latest VF/PF ABI version that
* drivers may use. Currently this is version 1.0.
*
* Some platforms may require different base VF/PF ABI version.
* No supported VF/PF ABI version can be 0.0.
*/
#define GUC_RELAY_VERSION_BASE_MAJOR 1
#define GUC_RELAY_VERSION_BASE_MINOR 0
#define GUC_RELAY_VERSION_LATEST_MAJOR 1
#define GUC_RELAY_VERSION_LATEST_MINOR 0
/**
* DOC: GuC Relay Actions
*
* The following actions are supported from VF/PF ABI version 1.0:
*
* * `VF2PF_HANDSHAKE`_
* * `VF2PF_QUERY_RUNTIME`_
*/
/**
* DOC: VF2PF_HANDSHAKE
*
* This `Relay Message`_ is used by the VF to establish ABI version with the PF.
*
* Prior to exchanging any other messages, both VF driver and PF driver must
* negotiate the VF/PF ABI version that will be used in their communication.
*
* The VF driver shall use @MAJOR and @MINOR fields to pass requested ABI version.
* The VF driver may use special version 0.0 (both @MAJOR and @MINOR set to 0)
* to request latest (or any) ABI version that is supported by the PF driver.
*
* This message definition shall be supported by all future ABI versions.
* This message definition shall not be changed by future ABI versions.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = MBZ |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_RELAY_ACTION_VF2PF_HANDSHAKE` = 0x0001 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:16 | **MAJOR** - requested major version of the VFPF interface |
* | | | (use MAJOR_ANY to request latest version supported by PF) |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | **MINOR** - requested minor version of the VFPF interface |
* | | | (use MINOR_ANY to request latest version supported by PF) |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = MBZ |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:16 | **MAJOR** - agreed major version of the VFPF interface |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | **MINOR** - agreed minor version of the VFPF interface |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_RELAY_ACTION_VF2PF_HANDSHAKE 0x0001u
#define VF2PF_HANDSHAKE_REQUEST_MSG_LEN 2u
#define VF2PF_HANDSHAKE_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0
#define VF2PF_HANDSHAKE_REQUEST_MSG_1_MAJOR (0xffffu << 16)
#define VF2PF_HANDSHAKE_MAJOR_ANY 0
#define VF2PF_HANDSHAKE_REQUEST_MSG_1_MINOR (0xffffu << 0)
#define VF2PF_HANDSHAKE_MINOR_ANY 0
#define VF2PF_HANDSHAKE_RESPONSE_MSG_LEN 2u
#define VF2PF_HANDSHAKE_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0
#define VF2PF_HANDSHAKE_RESPONSE_MSG_1_MAJOR (0xffffu << 16)
#define VF2PF_HANDSHAKE_RESPONSE_MSG_1_MINOR (0xffffu << 0)
/**
* DOC: VF2PF_QUERY_RUNTIME
*
* This `Relay Message`_ is used by the VF to query values of runtime registers.
*
* On some platforms, VF drivers may not have access to the some fuse registers
* (referred here as 'runtime registers') and therefore VF drivers need to ask
* the PF driver to obtain their values.
*
* However, the list of such registers, and their values, is fully owned and
* maintained by the PF driver and the VF driver may only initiate the query
* sequence and indicate in the @START field the starting index of the next
* requested register from this predefined list.
*
* In the response, the PF driver will return tuple of 32-bit register offset and
* the 32-bit value of that register (respectively @REG_OFFSET and @REG_VALUE).
*
* The VF driver can use @LIMIT field to limit number of returned register tuples.
* If @LIMIT is unset then PF decides about number of returned register tuples.
*
* This message definition is supported from ABI version 1.0.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | DATA0 = **LIMIT** - limit number of returned entries |
* | | | (use zero to not enforce any limits on the response) |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`GUC_RELAY_ACTION_VF2PF_QUERY_RUNTIME` = 0x0101 |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | DATA1 = **START** - index of the first requested entry |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = **COUNT** - number of entries included in response |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | DATA1 = **REMAINING** - number of remaining entries |
* +---+-------+--------------------------------------------------------------+
* | 2 | 31:0 | DATA2 = **REG_OFFSET** - offset of register[START] |
* +---+-------+--------------------------------------------------------------+
* | 3 | 31:0 | DATA3 = **REG_VALUE** - value of register[START] |
* +---+-------+--------------------------------------------------------------+
* | | | |
* +---+-------+--------------------------------------------------------------+
* |n-1| 31:0 | REG_OFFSET - offset of register[START + x] |
* +---+-------+--------------------------------------------------------------+
* | n | 31:0 | REG_VALUE - value of register[START + x] |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_RELAY_ACTION_VF2PF_QUERY_RUNTIME 0x0101u
#define VF2PF_QUERY_RUNTIME_REQUEST_MSG_LEN 2u
#define VF2PF_QUERY_RUNTIME_REQUEST_MSG_0_LIMIT GUC_HXG_REQUEST_MSG_0_DATA0
#define VF2PF_QUERY_RUNTIME_NO_LIMIT 0u
#define VF2PF_QUERY_RUNTIME_REQUEST_MSG_1_START GUC_HXG_REQUEST_MSG_n_DATAn
#define VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN (GUC_HXG_MSG_MIN_LEN + 1u)
#define VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MAX_LEN \
(VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN + VF2PF_QUERY_RUNTIME_MAX_COUNT * 2)
#define VF2PF_QUERY_RUNTIME_RESPONSE_MSG_0_COUNT GUC_HXG_RESPONSE_MSG_0_DATA0
#define VF2PF_QUERY_RUNTIME_MIN_COUNT 0
#define VF2PF_QUERY_RUNTIME_MAX_COUNT \
((GUC_RELAY_MSG_MAX_LEN - VF2PF_QUERY_RUNTIME_RESPONSE_MSG_MIN_LEN) / 2)
#define VF2PF_QUERY_RUNTIME_RESPONSE_MSG_1_REMAINING GUC_HXG_RESPONSE_MSG_n_DATAn
#define VF2PF_QUERY_RUNTIME_RESPONSE_DATAn_REG_OFFSETx GUC_HXG_RESPONSE_MSG_n_DATAn
#define VF2PF_QUERY_RUNTIME_RESPONSE_DATAn_REG_VALUEx GUC_HXG_RESPONSE_MSG_n_DATAn
/**
* DOC: GuC Relay Debug Actions
*
* This range of action codes is reserved for debugging purposes only and should
* be used only on debug builds. These actions may not be supported by the
* production drivers. Their definitions could be changed in the future.
*
* _`GUC_RELAY_ACTION_DEBUG_ONLY_START` = 0xDEB0
* _`GUC_RELAY_ACTION_DEBUG_ONLY_END` = 0xDEFF
*/
#define GUC_RELAY_ACTION_DEBUG_ONLY_START 0xDEB0
#define GUC_RELAY_ACTION_DEBUG_ONLY_END 0xDEFF
/**
* DOC: VFXPF_TESTLOOP
*
* This `Relay Message`_ is used to selftest the `GuC Relay Communication`_.
*
* The following opcodes are defined:
* VFXPF_TESTLOOP_OPCODE_NOP_ will return no data.
* VFXPF_TESTLOOP_OPCODE_BUSY_ will reply with BUSY response first.
* VFXPF_TESTLOOP_OPCODE_RETRY_ will reply with RETRY response instead.
* VFXPF_TESTLOOP_OPCODE_ECHO_ will return same data as received.
* VFXPF_TESTLOOP_OPCODE_FAIL_ will always fail with error.
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ or GUC_HXG_TYPE_FAST_REQUEST_ |
* | | | or GUC_HXG_TYPE_EVENT_ |
* | +-------+--------------------------------------------------------------+
* | | 27:16 | **OPCODE** |
* | | | - _`VFXPF_TESTLOOP_OPCODE_NOP` = 0x0 |
* | | | - _`VFXPF_TESTLOOP_OPCODE_BUSY` = 0xB |
* | | | - _`VFXPF_TESTLOOP_OPCODE_RETRY` = 0xD |
* | | | - _`VFXPF_TESTLOOP_OPCODE_ECHO` = 0xE |
* | | | - _`VFXPF_TESTLOOP_OPCODE_FAIL` = 0xF |
* | +-------+--------------------------------------------------------------+
* | | 15:0 | ACTION = _`IOV_ACTION_SELFTEST_RELAY` |
* +---+-------+--------------------------------------------------------------+
* | 1 | 31:0 | **DATA1** = optional, depends on **OPCODE**: |
* | | | for VFXPF_TESTLOOP_OPCODE_BUSY_: time in ms for reply |
* | | | for VFXPF_TESTLOOP_OPCODE_FAIL_: expected error |
* | | | for VFXPF_TESTLOOP_OPCODE_ECHO_: payload |
* +---+-------+--------------------------------------------------------------+
* |...| 31:0 | **DATAn** = only for **OPCODE** VFXPF_TESTLOOP_OPCODE_ECHO_ |
* +---+-------+--------------------------------------------------------------+
*
* +---+-------+--------------------------------------------------------------+
* | | Bits | Description |
* +===+=======+==============================================================+
* | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ |
* | +-------+--------------------------------------------------------------+
* | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ |
* | +-------+--------------------------------------------------------------+
* | | 27:0 | DATA0 = MBZ |
* +---+-------+--------------------------------------------------------------+
* |...| 31:0 | DATAn = only for **OPCODE** VFXPF_TESTLOOP_OPCODE_ECHO_ |
* +---+-------+--------------------------------------------------------------+
*/
#define GUC_RELAY_ACTION_VFXPF_TESTLOOP (GUC_RELAY_ACTION_DEBUG_ONLY_START + 1)
#define VFXPF_TESTLOOP_OPCODE_NOP 0x0
#define VFXPF_TESTLOOP_OPCODE_BUSY 0xB
#define VFXPF_TESTLOOP_OPCODE_RETRY 0xD
#define VFXPF_TESTLOOP_OPCODE_ECHO 0xE
#define VFXPF_TESTLOOP_OPCODE_FAIL 0xF
#endif
@@ -0,0 +1,118 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _ABI_GUC_RELAY_COMMUNICATION_ABI_H
#define _ABI_GUC_RELAY_COMMUNICATION_ABI_H
#include <linux/build_bug.h>
#include "guc_actions_sriov_abi.h"
#include "guc_communication_ctb_abi.h"
#include "guc_messages_abi.h"
/**
* DOC: GuC Relay Communication
*
* The communication between Virtual Function (VF) drivers and Physical Function
* (PF) drivers is based on the GuC firmware acting as a proxy (relay) agent.
*
* To communicate with the PF driver, VF's drivers use `VF2GUC_RELAY_TO_PF`_
* action that takes the `Relay Message`_ as opaque payload and requires the
* relay message identifier (RID) as additional parameter.
*
* This identifier is used by the drivers to match related messages.
*
* The GuC forwards this `Relay Message`_ and its identifier to the PF driver
* in `GUC2PF_RELAY_FROM_VF`_ action. This event message additionally contains
* the identifier of the origin VF (VFID).
*
* Likewise, to communicate with the VF drivers, PF driver use
* `VF2GUC_RELAY_TO_PF`_ action that in addition to the `Relay Message`_
* and the relay message identifier (RID) also takes the target VF identifier.
*
* The GuC uses this target VFID from the message to select where to send the
* `GUC2VF_RELAY_FROM_PF`_ with the embedded `Relay Message`_ with response::
*
* VF GuC PF
* | | |
* [ ] VF2GUC_RELAY_TO_PF | |
* [ ]---------------------------> [ ] |
* [ ] { rid, msg } [ ] |
* [ ] [ ] GUC2PF_RELAY_FROM_VF |
* [ ] [ ]---------------------------> [ ]
* [ ] | { VFID, rid, msg } [ ]
* [ ] | [ ]
* [ ] | PF2GUC_RELAY_TO_VF [ ]
* [ ] [ ] <---------------------------[ ]
* [ ] [ ] { VFID, rid, reply } |
* [ ] GUC2VF_RELAY_FROM_PF [ ] |
* [ ] <---------------------------[ ] |
* | { rid, reply } | |
* | | |
*
* It is also possible that PF driver will initiate communication with the
* selected VF driver. The same GuC action messages will be used::
*
* VF GuC PF
* | | |
* | | PF2GUC_RELAY_TO_VF [ ]
* | [ ] <---------------------------[ ]
* | [ ] { VFID, rid, msg } [ ]
* | GUC2VF_RELAY_FROM_PF [ ] [ ]
* [ ] <---------------------------[ ] [ ]
* [ ] { rid, msg } | [ ]
* [ ] | [ ]
* [ ] VF2GUC_RELAY_TO_PF | [ ]
* [ ]---------------------------> [ ] [ ]
* | { rid, reply } [ ] [ ]
* | [ ] GUC2PF_RELAY_FROM_VF [ ]
* | [ ]---------------------------> [ ]
* | | { VFID, rid, reply } |
* | | |
*/
/**
* DOC: Relay Message
*
* The `Relay Message`_ is used by Physical Function (PF) driver and Virtual
* Function (VF) drivers to communicate using `GuC Relay Communication`_.
*
* Format of the `Relay Message`_ follows format of the generic `HXG Message`_.
*
* +--------------------------------------------------------------------------+
* | `Relay Message`_ |
* +==========================================================================+
* | `HXG Message`_ |
* +--------------------------------------------------------------------------+
*
* Maximum length of the `Relay Message`_ is limited by the maximum length of
* the `CTB HXG Message`_ and format of the `GUC2PF_RELAY_FROM_VF`_ message.
*/
#define GUC_RELAY_MSG_MIN_LEN GUC_HXG_MSG_MIN_LEN
#define GUC_RELAY_MSG_MAX_LEN \
(GUC_CTB_MAX_DWORDS - GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN)
static_assert(PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN >
VF2GUC_RELAY_TO_PF_REQUEST_MSG_MIN_LEN);
/**
* DOC: Relay Error Codes
*
* The `GuC Relay Communication`_ can be used to pass `Relay Message`_ between
* drivers that run on different Operating Systems. To help in troubleshooting,
* `GuC Relay Communication`_ uses error codes that mostly match errno values.
*/
#define GUC_RELAY_ERROR_UNDISCLOSED 0
#define GUC_RELAY_ERROR_OPERATION_NOT_PERMITTED 1 /* EPERM */
#define GUC_RELAY_ERROR_PERMISSION_DENIED 13 /* EACCES */
#define GUC_RELAY_ERROR_INVALID_ARGUMENT 22 /* EINVAL */
#define GUC_RELAY_ERROR_INVALID_REQUEST_CODE 56 /* EBADRQC */
#define GUC_RELAY_ERROR_NO_DATA_AVAILABLE 61 /* ENODATA */
#define GUC_RELAY_ERROR_PROTOCOL_ERROR 71 /* EPROTO */
#define GUC_RELAY_ERROR_MESSAGE_SIZE 90 /* EMSGSIZE */
#endif
@@ -0,0 +1,57 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2025 Intel Corporation
*/
#ifndef _ABI_GUC_SCHEDULER_ABI_H
#define _ABI_GUC_SCHEDULER_ABI_H
#include <linux/types.h>
/*
* Generic defines required for registration with and submissions to the GuC
* scheduler. Includes engine class/instance defines and context attributes
* (id, priority, etc)
*/
/* Engine classes/instances */
#define GUC_RENDER_CLASS 0
#define GUC_VIDEO_CLASS 1
#define GUC_VIDEOENHANCE_CLASS 2
#define GUC_BLITTER_CLASS 3
#define GUC_COMPUTE_CLASS 4
#define GUC_GSC_OTHER_CLASS 5
#define GUC_LAST_ENGINE_CLASS GUC_GSC_OTHER_CLASS
#define GUC_MAX_ENGINE_CLASSES 16
#define GUC_MAX_INSTANCES_PER_CLASS 32
/* context priority values */
#define GUC_CLIENT_PRIORITY_KMD_HIGH 0
#define GUC_CLIENT_PRIORITY_HIGH 1
#define GUC_CLIENT_PRIORITY_KMD_NORMAL 2
#define GUC_CLIENT_PRIORITY_NORMAL 3
#define GUC_CLIENT_PRIORITY_NUM 4
/* Context registration */
#define GUC_ID_MAX 65535
#define GUC_ID_UNKNOWN 0xffffffff
#define CONTEXT_REGISTRATION_FLAG_KMD BIT(0)
#define CONTEXT_REGISTRATION_FLAG_TYPE GENMASK(2, 1)
#define GUC_CONTEXT_NORMAL 0
#define GUC_CONTEXT_COMPRESSION_SAVE 1
#define GUC_CONTEXT_COMPRESSION_RESTORE 2
#define GUC_CONTEXT_COUNT (GUC_CONTEXT_COMPRESSION_RESTORE + 1)
/* context enable/disable */
#define GUC_CONTEXT_DISABLE 0
#define GUC_CONTEXT_ENABLE 1
/* scheduler groups */
#define GUC_MAX_SCHED_GROUPS 8
struct guc_sched_group {
u32 engines[GUC_MAX_ENGINE_CLASSES];
} __packed;
#endif
@@ -0,0 +1,405 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2022 Intel Corporation
*/
#ifndef _ABI_UC_FW_ABI_H
#define _ABI_UC_FW_ABI_H
#include <linux/build_bug.h>
#include <linux/types.h>
/**
* DOC: CSS-based Firmware Layout
*
* The CSS-based firmware structure is used for GuC releases on all platforms
* and for HuC releases up to DG1. Starting from DG2/MTL the HuC uses the GSC
* layout instead.
* The CSS firmware layout looks like this::
*
* +======================================================================+
* | Firmware blob |
* +===============+===============+============+============+============+
* | CSS header | uCode | RSA key | modulus | exponent |
* +===============+===============+============+============+============+
* <-header size-> <---header size continued ----------->
* <--- size ----------------------------------------------------------->
* <-key size->
* <-mod size->
* <-exp size->
*
* The firmware may or may not have modulus key and exponent data. The header,
* uCode and RSA signature are must-have components that will be used by driver.
* Length of each components, which is all in dwords, can be found in header.
* In the case that modulus and exponent are not present in fw, a.k.a truncated
* image, the length value still appears in header.
*
* Driver will do some basic fw size validation based on the following rules:
*
* 1. Header, uCode and RSA are must-have components.
* 2. All firmware components, if they present, are in the sequence illustrated
* in the layout table above.
* 3. Length info of each component can be found in header, in dwords.
* 4. Modulus and exponent key are not required by driver. They may not appear
* in fw. So driver will load a truncated firmware in this case.
*/
struct uc_css_rsa_info {
u32 key_size_dw;
u32 modulus_size_dw;
u32 exponent_size_dw;
} __packed;
struct uc_css_guc_info {
u32 time;
#define CSS_TIME_HOUR (0xFF << 0)
#define CSS_TIME_MIN (0xFF << 8)
#define CSS_TIME_SEC (0xFFFF << 16)
u32 reserved0[5];
u32 sw_version;
#define CSS_SW_VERSION_UC_MAJOR (0xFF << 16)
#define CSS_SW_VERSION_UC_MINOR (0xFF << 8)
#define CSS_SW_VERSION_UC_PATCH (0xFF << 0)
u32 submission_version;
u32 reserved1[11];
u32 header_info;
#define CSS_HEADER_INFO_SVN (0xFF)
#define CSS_HEADER_INFO_COPY_VALID (0x1 << 31)
u32 private_data_size;
u32 ukernel_info;
#define CSS_UKERNEL_INFO_DEVICEID (0xFFFF << 16)
#define CSS_UKERNEL_INFO_PRODKEY (0xFF << 8)
#define CSS_UKERNEL_INFO_BUILDTYPE (0x3 << 2)
#define CSS_UKERNEL_INFO_BUILDTYPE_PROD 0
#define CSS_UKERNEL_INFO_BUILDTYPE_PREPROD 1
#define CSS_UKERNEL_INFO_BUILDTYPE_DEBUG 2
#define CSS_UKERNEL_INFO_ENCSTATUS (0x1 << 1)
#define CSS_UKERNEL_INFO_COPY_VALID (0x1 << 0)
} __packed;
struct uc_css_header {
u32 module_type;
/*
* header_size includes all non-uCode bits, including css_header, rsa
* key, modulus key and exponent data.
*/
u32 header_size_dw;
u32 header_version;
u32 reserved0;
u32 module_vendor;
u32 date;
#define CSS_DATE_DAY (0xFF << 0)
#define CSS_DATE_MONTH (0xFF << 8)
#define CSS_DATE_YEAR (0xFFFF << 16)
u32 size_dw; /* uCode plus header_size_dw */
union {
u32 reserved1[3];
struct uc_css_rsa_info rsa_info;
};
union {
u32 reserved2[22];
struct uc_css_guc_info guc_info;
};
} __packed;
static_assert(sizeof(struct uc_css_header) == 128);
/**
* DOC: GSC-based Firmware Layout
*
* The GSC-based firmware structure is used for GSC releases on all platforms
* and for HuC releases starting from DG2/MTL. Older HuC releases use the
* CSS-based layout instead. Differently from the CSS headers, the GSC headers
* uses a directory + entries structure (i.e., there is array of addresses
* pointing to specific header extensions identified by a name). Although the
* header structures are the same, some of the entries are specific to GSC while
* others are specific to HuC. The manifest header entry, which includes basic
* information about the binary (like the version) is always present, but it is
* named differently based on the binary type.
*
* The HuC binary starts with a Code Partition Directory (CPD) header. The
* entries we're interested in for use in the driver are:
*
* 1. "HUCP.man": points to the manifest header for the HuC.
* 2. "huc_fw": points to the FW code. On platforms that support load via DMA
* and 2-step HuC authentication (i.e. MTL+) this is a full CSS-based binary,
* while if the GSC is the one doing the load (which only happens on DG2)
* this section only contains the uCode.
*
* The GSC-based HuC firmware layout looks like this::
*
* +================================================+
* | CPD Header |
* +================================================+
* | CPD entries[] |
* | entry1 |
* | ... |
* | entryX |
* | "HUCP.man" |
* | ... |
* | offset >----------------------------|------o
* | ... | |
* | entryY | |
* | "huc_fw" | |
* | ... | |
* | offset >----------------------------|----------o
* +================================================+ | |
* | |
* +================================================+ | |
* | Manifest Header |<-----o |
* | ... | |
* | FW version | |
* | ... | |
* +================================================+ |
* |
* +================================================+ |
* | FW binary |<---------o
* | CSS (MTL+ only) |
* | uCode |
* | RSA Key (MTL+ only) |
* | ... |
* +================================================+
*
* The GSC binary starts instead with a layout header, which contains the
* locations of the various partitions of the binary. The one we're interested
* in is the boot1 partition, where we can find a BPDT header followed by
* entries, one of which points to the RBE sub-section of the partition, which
* contains the CPD. The GSC blob does not contain a CSS-based binary, so we
* only need to look for the manifest, which is under the "RBEP.man" CPD entry.
* Note that we have no need to find where the actual FW code is inside the
* image because the GSC ROM will itself parse the headers to find it and load
* it.
* The GSC firmware header layout looks like this::
*
* +================================================+
* | Layout Pointers |
* | ... |
* | Boot1 offset >---------------------------|------o
* | ... | |
* +================================================+ |
* |
* +================================================+ |
* | BPDT header |<-----o
* +================================================+
* | BPDT entries[] |
* | entry1 |
* | ... |
* | entryX |
* | type == GSC_RBE |
* | offset >-----------------------------|------o
* | ... | |
* +================================================+ |
* |
* +================================================+ |
* | CPD Header |<-----o
* +================================================+
* | CPD entries[] |
* | entry1 |
* | ... |
* | entryX |
* | "RBEP.man" |
* | ... |
* | offset >----------------------------|------o
* | ... | |
* +================================================+ |
* |
* +================================================+ |
* | Manifest Header |<-----o
* | ... |
* | FW version |
* | ... |
* | Security version |
* | ... |
* +================================================+
*/
struct gsc_version {
u16 major;
u16 minor;
u16 hotfix;
u16 build;
} __packed;
struct gsc_partition {
u32 offset;
u32 size;
} __packed;
struct gsc_layout_pointers {
u8 rom_bypass_vector[16];
/* size of this header section, not including ROM bypass vector */
u16 size;
/*
* bit0: Backup copy of layout pointers exists
* bits1-15: reserved
*/
u8 flags;
u8 reserved;
u32 crc32;
struct gsc_partition datap;
struct gsc_partition boot1;
struct gsc_partition boot2;
struct gsc_partition boot3;
struct gsc_partition boot4;
struct gsc_partition boot5;
struct gsc_partition temp_pages;
} __packed;
/* Boot partition structures */
struct gsc_bpdt_header {
u32 signature;
#define GSC_BPDT_HEADER_SIGNATURE 0x000055AA
u16 descriptor_count; /* num of entries after the header */
u8 version;
u8 configuration;
u32 crc32;
u32 build_version;
struct gsc_version tool_version;
} __packed;
struct gsc_bpdt_entry {
/*
* Bits 0-15: BPDT entry type
* Bits 16-17: reserved
* Bit 18: code sub-partition
* Bits 19-31: reserved
*/
u32 type;
#define GSC_BPDT_ENTRY_TYPE_MASK GENMASK(15, 0)
#define GSC_BPDT_ENTRY_TYPE_GSC_RBE 0x1
u32 sub_partition_offset; /* from the base of the BPDT header */
u32 sub_partition_size;
} __packed;
/* Code partition directory (CPD) structures */
struct gsc_cpd_header_v2 {
u32 header_marker;
#define GSC_CPD_HEADER_MARKER 0x44504324
u32 num_of_entries;
u8 header_version;
u8 entry_version;
u8 header_length; /* in bytes */
u8 flags;
u32 partition_name;
u32 crc32;
} __packed;
struct gsc_cpd_entry {
u8 name[12];
/*
* Bits 0-24: offset from the beginning of the code partition
* Bit 25: huffman compressed
* Bits 26-31: reserved
*/
u32 offset;
#define GSC_CPD_ENTRY_OFFSET_MASK GENMASK(24, 0)
#define GSC_CPD_ENTRY_HUFFMAN_COMP BIT(25)
/*
* Module/Item length, in bytes. For Huffman-compressed modules, this
* refers to the uncompressed size. For software-compressed modules,
* this refers to the compressed size.
*/
u32 length;
u8 reserved[4];
} __packed;
struct gsc_manifest_header {
u32 header_type; /* 0x4 for manifest type */
u32 header_length; /* in dwords */
u32 header_version;
u32 flags;
u32 vendor;
u32 date;
u32 size; /* In dwords, size of entire manifest (header + extensions) */
u32 header_id;
u32 internal_data;
struct gsc_version fw_version;
u32 security_version;
struct gsc_version meu_kit_version;
u32 meu_manifest_version;
u8 general_data[4];
u8 reserved3[56];
u32 modulus_size; /* in dwords */
u32 exponent_size; /* in dwords */
} __packed;
/**
* DOC: Late binding Firmware Layout
*
* The Late binding binary starts with FPT header, which contains locations
* of various partitions of the binary. Here we're interested in finding out
* manifest version. To the manifest version, we need to locate CPD header
* one of the entry in CPD header points to manifest header. Manifest header
* contains the version.
*
* +================================================+
* | FPT Header |
* +================================================+
* | FPT entries[] |
* | entry1 |
* | ... |
* | entryX |
* | "LTES" |
* | ... |
* | offset >-----------------------------|------o
* +================================================+ |
* |
* +================================================+ |
* | CPD Header |<-----o
* +================================================+
* | CPD entries[] |
* | entry1 |
* | ... |
* | entryX |
* | "LTES.man" |
* | ... |
* | offset >----------------------------|------o
* +================================================+ |
* |
* +================================================+ |
* | Manifest Header |<-----o
* | ... |
* | FW version |
* | ... |
* +================================================+
*/
/* FPT Headers */
struct csc_fpt_header {
u32 header_marker;
#define CSC_FPT_HEADER_MARKER 0x54504624
u32 num_of_entries;
u8 header_version;
u8 entry_version;
u8 header_length; /* in bytes */
u8 flags;
u16 ticks_to_add;
u16 tokens_to_add;
u32 uma_size;
u32 crc32;
struct gsc_version fitc_version;
} __packed;
struct csc_fpt_entry {
u8 name[4]; /* partition name */
u32 reserved1;
u32 offset; /* offset from beginning of CSE region */
u32 length; /* partition length in bytes */
u32 reserved2[3];
u32 partition_flags;
} __packed;
#endif
@@ -0,0 +1,65 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2026 Intel Corporation
*/
#ifndef _XE_SYSCTRL_ABI_H_
#define _XE_SYSCTRL_ABI_H_
#include <linux/types.h>
/**
* DOC: System Controller ABI
*
* This header defines the Application Binary Interface (ABI) used by
* drm/xe to communicate with System Controller firmware on Intel Xe3p
* discrete GPU platforms.
*
* System Controller (sysctrl) is a firmware-managed entity on Intel
* dGPUs responsible for certain low-level platform management
* functions.
*
* Communication protocol:
*
* Communication uses a mailbox interface with messages composed of:
*
* - Application message header (struct xe_sysctrl_app_msg_hdr)
* containing group_id, command, and version
* - Variable-length, command-specific payload
*
* Message header format:
*
* The 32-bit application message header is packed as:
*
* - Bits [7:0] : Group ID identifying command group
* - Bits [15:8] : Command identifier within group
* - Bits [23:16] : Command version for interface compatibility
* - Bits [31:24] : Reserved, must be zero
*
* This header defines firmware ABI message formats and constants shared
* between driver and System Controller firmware.
*/
/**
* struct xe_sysctrl_app_msg_hdr - Application layer message header
* @data: 32-bit header data
*
* Header structure for application-level messages.
*/
struct xe_sysctrl_app_msg_hdr {
u32 data;
} __packed;
#define SYSCTRL_HDR_GROUP_ID_MASK GENMASK(7, 0)
#define SYSCTRL_HDR_COMMAND_MASK GENMASK(14, 8)
#define SYSCTRL_HDR_COMMAND_MAX 0x7f
#define SYSCTRL_HDR_IS_RESPONSE BIT(15)
#define SYSCTRL_HDR_RESERVED_MASK GENMASK(23, 16)
#define SYSCTRL_HDR_RESULT_MASK GENMASK(31, 24)
#define APP_HDR_GROUP_ID_MASK GENMASK(7, 0)
#define APP_HDR_COMMAND_MASK GENMASK(15, 8)
#define APP_HDR_VERSION_MASK GENMASK(23, 16)
#define APP_HDR_RESERVED_MASK GENMASK(31, 24)
#endif
@@ -0,0 +1,16 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef __I915_CONFIG_H__
#define __I915_CONFIG_H__
#include <linux/sched.h>
static inline unsigned long i915_fence_timeout(void)
{
return MAX_SCHEDULE_TIMEOUT;
}
#endif /* __I915_CONFIG_H__ */
@@ -0,0 +1,7 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#include "../../i915/i915_gtt_view_types.h"
/* Partial view not supported in xe, fail build if used. */
#define I915_GTT_VIEW_PARTIAL
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#include "../../i915/i915_reg_defs.h"
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef __INTEL_CLOCK_GATING_H__
#define __INTEL_CLOCK_GATING_H__
struct drm_device;
static inline void intel_clock_gating_init(struct drm_device *drm) {}
static inline void intel_clock_gating_hooks_init(struct drm_device *drm) {}
#endif /* __INTEL_CLOCK_GATING_H__ */
@@ -0,0 +1,139 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef __INTEL_UNCORE_H__
#define __INTEL_UNCORE_H__
#include "i915_reg_defs.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_mmio.h"
static inline struct intel_uncore *to_intel_uncore(struct drm_device *drm)
{
return &to_xe_device(drm)->uncore;
}
static inline struct xe_mmio *__compat_uncore_to_mmio(struct intel_uncore *uncore)
{
struct xe_device *xe = container_of(uncore, struct xe_device, uncore);
return xe_root_tile_mmio(xe);
}
static inline u32 intel_uncore_read(struct intel_uncore *uncore,
i915_reg_t i915_reg)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
return xe_mmio_read32(__compat_uncore_to_mmio(uncore), reg);
}
static inline u8 intel_uncore_read8(struct intel_uncore *uncore,
i915_reg_t i915_reg)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
return xe_mmio_read8(__compat_uncore_to_mmio(uncore), reg);
}
static inline void intel_uncore_write8(struct intel_uncore *uncore,
i915_reg_t i915_reg, u8 val)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
xe_mmio_write8(__compat_uncore_to_mmio(uncore), reg, val);
}
static inline u16 intel_uncore_read16(struct intel_uncore *uncore,
i915_reg_t i915_reg)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
return xe_mmio_read16(__compat_uncore_to_mmio(uncore), reg);
}
static inline u64
intel_uncore_read64_2x32(struct intel_uncore *uncore,
i915_reg_t i915_lower_reg, i915_reg_t i915_upper_reg)
{
struct xe_reg lower_reg = XE_REG(i915_mmio_reg_offset(i915_lower_reg));
struct xe_reg upper_reg = XE_REG(i915_mmio_reg_offset(i915_upper_reg));
u32 upper, lower, old_upper;
int loop = 0;
upper = xe_mmio_read32(__compat_uncore_to_mmio(uncore), upper_reg);
do {
old_upper = upper;
lower = xe_mmio_read32(__compat_uncore_to_mmio(uncore), lower_reg);
upper = xe_mmio_read32(__compat_uncore_to_mmio(uncore), upper_reg);
} while (upper != old_upper && loop++ < 2);
return (u64)upper << 32 | lower;
}
static inline void intel_uncore_posting_read(struct intel_uncore *uncore,
i915_reg_t i915_reg)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
xe_mmio_read32(__compat_uncore_to_mmio(uncore), reg);
}
static inline void intel_uncore_write(struct intel_uncore *uncore,
i915_reg_t i915_reg, u32 val)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
xe_mmio_write32(__compat_uncore_to_mmio(uncore), reg, val);
}
static inline u32 intel_uncore_rmw(struct intel_uncore *uncore,
i915_reg_t i915_reg, u32 clear, u32 set)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
return xe_mmio_rmw32(__compat_uncore_to_mmio(uncore), reg, clear, set);
}
static inline u32 intel_uncore_read_fw(struct intel_uncore *uncore,
i915_reg_t i915_reg)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
return xe_mmio_read32(__compat_uncore_to_mmio(uncore), reg);
}
static inline void intel_uncore_write_fw(struct intel_uncore *uncore,
i915_reg_t i915_reg, u32 val)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
xe_mmio_write32(__compat_uncore_to_mmio(uncore), reg, val);
}
static inline u32 intel_uncore_read_notrace(struct intel_uncore *uncore,
i915_reg_t i915_reg)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
return xe_mmio_read32(__compat_uncore_to_mmio(uncore), reg);
}
static inline void intel_uncore_write_notrace(struct intel_uncore *uncore,
i915_reg_t i915_reg, u32 val)
{
struct xe_reg reg = XE_REG(i915_mmio_reg_offset(i915_reg));
xe_mmio_write32(__compat_uncore_to_mmio(uncore), reg, val);
}
static inline bool
intel_uncore_arm_unclaimed_mmio_detection(struct intel_uncore *uncore)
{
return false;
}
#endif /* __INTEL_UNCORE_H__ */
@@ -0,0 +1,6 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#define trace_i915_reg_rw(a...) do { } while (0)
@@ -0,0 +1,579 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2023 Intel Corporation
*/
#include "xe_display.h"
#include "regs/xe_irq_regs.h"
#include <linux/fb.h>
#include <drm/drm_client.h>
#include <drm/drm_client_event.h>
#include <drm/drm_drv.h>
#include <drm/drm_managed.h>
#include <drm/drm_probe_helper.h>
#include <drm/intel/display_member.h>
#include <drm/intel/display_parent_interface.h>
#include <uapi/drm/xe_drm.h>
#include "intel_acpi.h"
#include "intel_audio.h"
#include "intel_bw.h"
#include "intel_display.h"
#include "intel_display_core.h"
#include "intel_display_device.h"
#include "intel_display_driver.h"
#include "intel_display_irq.h"
#include "intel_display_types.h"
#include "intel_dmc.h"
#include "intel_dmc_wl.h"
#include "intel_dp.h"
#include "intel_dram.h"
#include "intel_encoder.h"
#include "intel_fbdev.h"
#include "intel_hdcp.h"
#include "intel_hotplug.h"
#include "intel_opregion.h"
#include "skl_watermark.h"
#include "xe_device.h"
#include "xe_display_bo.h"
#include "xe_display_pcode.h"
#include "xe_display_rpm.h"
#include "xe_dsb_buffer.h"
#include "xe_fb_pin.h"
#include "xe_frontbuffer.h"
#include "xe_hdcp_gsc.h"
#include "xe_initial_plane.h"
#include "xe_module.h"
#include "xe_panic.h"
#include "xe_stolen.h"
/* Ensure drm and display members are placed properly. */
INTEL_DISPLAY_MEMBER_STATIC_ASSERT(struct xe_device, drm, display);
/* Xe device functions */
/**
* xe_display_driver_probe_defer - Detect if we need to wait for other drivers
* early on
* @pdev: PCI device
*
* Note: This is called before xe or display device creation.
*
* Returns: true if probe needs to be deferred, false otherwise
*/
bool xe_display_driver_probe_defer(struct pci_dev *pdev)
{
if (!xe_modparam.probe_display)
return 0;
return intel_display_driver_probe_defer(pdev);
}
static void unset_display_features(struct xe_device *xe)
{
xe->drm.driver_features &= ~XE_DISPLAY_DRIVER_FEATURES;
}
static void xe_display_fini_early(void *arg)
{
struct xe_device *xe = arg;
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
intel_hpd_cancel_work(display);
intel_display_driver_remove_nogem(display);
intel_display_driver_remove_noirq(display);
intel_opregion_cleanup(display);
intel_display_power_cleanup(display);
}
int xe_display_init_early(struct xe_device *xe)
{
struct intel_display *display = xe->display;
int err;
if (!xe->info.probe_display)
return 0;
/* Fake uncore lock */
spin_lock_init(&xe->uncore.lock);
intel_display_driver_early_probe(display);
intel_display_device_info_runtime_init(display);
/* Display may have been disabled at runtime init */
if (!intel_display_device_present(display)) {
xe->info.probe_display = false;
unset_display_features(xe);
return 0;
}
/* Early display init.. */
intel_opregion_setup(display);
/*
* Fill the dram structure to get the system dram info. This will be
* used for memory latency calculation.
*/
err = intel_dram_detect(display);
if (err)
goto err_opregion;
intel_bw_init_hw(display);
err = intel_display_driver_probe_noirq(display);
if (err)
goto err_opregion;
err = intel_display_driver_probe_nogem(display);
if (err)
goto err_noirq;
return devm_add_action_or_reset(xe->drm.dev, xe_display_fini_early, xe);
err_noirq:
intel_display_driver_remove_noirq(display);
intel_display_power_cleanup(display);
err_opregion:
intel_opregion_cleanup(display);
return err;
}
static void xe_display_fini(void *arg)
{
struct xe_device *xe = arg;
struct intel_display *display = xe->display;
intel_hpd_poll_fini(display);
intel_hdcp_component_fini(display);
intel_audio_deinit(display);
intel_display_driver_remove(display);
}
int xe_display_init(struct xe_device *xe)
{
struct intel_display *display = xe->display;
int err;
if (!xe->info.probe_display)
return 0;
err = intel_display_driver_probe(display);
if (err)
return err;
return devm_add_action_or_reset(xe->drm.dev, xe_display_fini, xe);
}
void xe_display_register(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
intel_display_driver_register(display);
intel_display_power_enable(display);
}
void xe_display_unregister(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
intel_display_power_disable(display);
intel_display_driver_unregister(display);
}
/* IRQ-related functions */
void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
if (master_ctl & DISPLAY_IRQ)
intel_display_irq_handler(display, NULL);
}
void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
if (gu_misc_iir & GU_MISC_GSE)
intel_opregion_asle_intr(display);
}
void xe_display_irq_reset(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
intel_display_irq_reset(display);
}
void xe_display_irq_postinstall(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
intel_display_irq_postinstall(display);
}
static bool suspend_to_idle(void)
{
#if IS_ENABLED(CONFIG_ACPI_SLEEP)
if (acpi_target_system_state() < ACPI_STATE_S3)
return true;
#endif
return false;
}
static void xe_display_enable_d3cold(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
/*
* We do a lot of poking in a lot of registers, make sure they work
* properly.
*/
intel_display_power_disable(display);
intel_display_flush_cleanup_work(display);
intel_opregion_suspend(display, PCI_D3cold);
intel_dmc_suspend(display);
if (intel_display_device_present(display))
intel_hpd_poll_enable(display);
}
static void xe_display_disable_d3cold(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
intel_dmc_resume(display);
if (intel_display_device_present(display))
drm_mode_config_reset(&xe->drm);
intel_display_driver_init_hw(display);
intel_hpd_init(display);
if (intel_display_device_present(display))
intel_hpd_poll_disable(display);
intel_opregion_resume(display);
intel_display_power_enable(display);
}
void xe_display_pm_suspend(struct xe_device *xe)
{
struct intel_display *display = xe->display;
bool s2idle = suspend_to_idle();
if (!xe->info.probe_display)
return;
/*
* We do a lot of poking in a lot of registers, make sure they work
* properly.
*/
intel_display_power_disable(display);
drm_client_dev_suspend(&xe->drm);
if (intel_display_device_present(display)) {
drm_kms_helper_poll_disable(&xe->drm);
intel_display_driver_disable_user_access(display);
intel_display_driver_suspend(display);
}
intel_display_flush_cleanup_work(display);
intel_encoder_block_all_hpds(display);
intel_hpd_cancel_work(display);
if (intel_display_device_present(display)) {
intel_display_driver_suspend_access(display);
intel_encoder_suspend_all(display);
}
intel_opregion_suspend(display, s2idle ? PCI_D1 : PCI_D3cold);
intel_dmc_suspend(display);
}
void xe_display_pm_shutdown(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
intel_display_power_disable(display);
drm_client_dev_suspend(&xe->drm);
if (intel_display_device_present(display)) {
drm_kms_helper_poll_disable(&xe->drm);
intel_display_driver_disable_user_access(display);
intel_display_driver_suspend(display);
}
intel_display_flush_cleanup_work(display);
intel_dp_mst_suspend(display);
intel_encoder_block_all_hpds(display);
intel_hpd_cancel_work(display);
if (intel_display_device_present(display))
intel_display_driver_suspend_access(display);
intel_encoder_suspend_all(display);
intel_encoder_shutdown_all(display);
intel_opregion_suspend(display, PCI_D3cold);
intel_dmc_suspend(display);
}
void xe_display_pm_runtime_suspend(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
if (xe->d3cold.allowed) {
xe_display_enable_d3cold(xe);
return;
}
intel_hpd_poll_enable(display);
}
void xe_display_pm_suspend_late(struct xe_device *xe)
{
struct intel_display *display = xe->display;
bool s2idle = suspend_to_idle();
if (!xe->info.probe_display)
return;
intel_display_power_suspend_late(display, s2idle);
}
void xe_display_pm_runtime_suspend_late(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
if (xe->d3cold.allowed)
xe_display_pm_suspend_late(xe);
/*
* If xe_display_pm_suspend_late() is not called, it is likely
* that we will be on dynamic DC states with DMC wakelock enabled. We
* need to flush the release work in that case.
*/
intel_dmc_wl_flush_release_work(display);
}
void xe_display_pm_shutdown_late(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
/*
* The only requirement is to reboot with display DC states disabled,
* for now leaving all display power wells in the INIT power domain
* enabled.
*/
intel_display_power_driver_remove(display);
}
void xe_display_pm_resume_early(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
intel_display_power_resume_early(display);
}
void xe_display_pm_resume(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
intel_dmc_resume(display);
if (intel_display_device_present(display))
drm_mode_config_reset(&xe->drm);
intel_display_driver_init_hw(display);
if (intel_display_device_present(display))
intel_display_driver_resume_access(display);
intel_hpd_init(display);
intel_encoder_unblock_all_hpds(display);
if (intel_display_device_present(display)) {
intel_display_driver_resume(display);
drm_kms_helper_poll_enable(&xe->drm);
intel_display_driver_enable_user_access(display);
}
if (intel_display_device_present(display))
intel_hpd_poll_disable(display);
intel_opregion_resume(display);
drm_client_dev_resume(&xe->drm);
intel_display_power_enable(display);
}
void xe_display_pm_runtime_resume(struct xe_device *xe)
{
struct intel_display *display = xe->display;
if (!xe->info.probe_display)
return;
if (xe->d3cold.allowed) {
xe_display_disable_d3cold(xe);
return;
}
intel_hpd_init(display);
intel_hpd_poll_disable(display);
skl_watermark_ipc_update(display);
}
static void display_device_remove(struct drm_device *dev, void *arg)
{
struct xe_device *xe = arg;
intel_display_device_remove(xe->display);
xe->display = NULL;
}
static bool irq_enabled(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
return atomic_read(&xe->irq.enabled);
}
static void irq_synchronize(struct drm_device *drm)
{
synchronize_irq(to_pci_dev(drm->dev)->irq);
}
static const struct intel_display_irq_interface xe_display_irq_interface = {
.enabled = irq_enabled,
.synchronize = irq_synchronize,
};
static bool has_auxccs(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
return xe->info.platform == XE_ALDERLAKE_P;
}
static const struct intel_display_parent_interface parent = {
.bo = &xe_display_bo_interface,
.dsb = &xe_display_dsb_interface,
.fb_pin = &xe_display_fb_pin_interface,
.frontbuffer = &xe_display_frontbuffer_interface,
.hdcp = &xe_display_hdcp_interface,
.initial_plane = &xe_display_initial_plane_interface,
.irq = &xe_display_irq_interface,
.panic = &xe_display_panic_interface,
.pcode = &xe_display_pcode_interface,
.rpm = &xe_display_rpm_interface,
.stolen = &xe_display_stolen_interface,
.has_auxccs = has_auxccs,
};
/**
* xe_display_probe - probe display and create display struct
* @xe: XE device instance
*
* Initialize all fields used by the display part.
*
* TODO: once everything can be inside a single struct, make the struct opaque
* to the rest of xe and return it to be xe->display.
*
* Returns: 0 on success
*/
int xe_display_probe(struct xe_device *xe)
{
struct pci_dev *pdev = to_pci_dev(xe->drm.dev);
struct intel_display *display;
int err;
if (!xe->info.probe_display)
goto no_display;
display = intel_display_device_probe(pdev, &parent);
if (IS_ERR(display))
return PTR_ERR(display);
xe->display = display;
err = drmm_add_action_or_reset(&xe->drm, display_device_remove, xe);
if (err)
return err;
if (intel_display_device_present(display))
return 0;
no_display:
xe->info.probe_display = false;
unset_display_features(xe);
return 0;
}
#ifdef CONFIG_DRM_FBDEV_EMULATION
int xe_display_driver_fbdev_probe(struct drm_fb_helper *fbh,
struct drm_fb_helper_surface_size *sizes)
{
return intel_fbdev_driver_fbdev_probe(fbh, sizes);
}
#endif
@@ -0,0 +1,84 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_DISPLAY_H_
#define _XE_DISPLAY_H_
#include <linux/types.h>
struct drm_driver;
struct drm_fb_helper;
struct drm_fb_helper_surface_size;
struct pci_dev;
struct xe_device;
#if IS_ENABLED(CONFIG_DRM_XE_DISPLAY)
bool xe_display_driver_probe_defer(struct pci_dev *pdev);
int xe_display_driver_fbdev_probe(struct drm_fb_helper *fbh,
struct drm_fb_helper_surface_size *sizes);
int xe_display_probe(struct xe_device *xe);
int xe_display_init_early(struct xe_device *xe);
int xe_display_init(struct xe_device *xe);
void xe_display_register(struct xe_device *xe);
void xe_display_unregister(struct xe_device *xe);
void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl);
void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir);
void xe_display_irq_reset(struct xe_device *xe);
void xe_display_irq_postinstall(struct xe_device *xe);
void xe_display_pm_suspend(struct xe_device *xe);
void xe_display_pm_shutdown(struct xe_device *xe);
void xe_display_pm_suspend_late(struct xe_device *xe);
void xe_display_pm_shutdown_late(struct xe_device *xe);
void xe_display_pm_resume_early(struct xe_device *xe);
void xe_display_pm_resume(struct xe_device *xe);
void xe_display_pm_runtime_suspend(struct xe_device *xe);
void xe_display_pm_runtime_suspend_late(struct xe_device *xe);
void xe_display_pm_runtime_resume(struct xe_device *xe);
#define XE_DISPLAY_DRIVER_FEATURES (DRIVER_MODESET | DRIVER_ATOMIC)
#define XE_DISPLAY_DRIVER_OPS \
.fbdev_probe = PTR_IF(IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION), \
xe_display_driver_fbdev_probe)
#else
#define XE_DISPLAY_DRIVER_FEATURES 0
#define XE_DISPLAY_DRIVER_OPS \
.fbdev_probe = NULL
static inline int xe_display_driver_probe_defer(struct pci_dev *pdev) { return 0; }
static inline int xe_display_probe(struct xe_device *xe) { return 0; }
static inline int xe_display_init_early(struct xe_device *xe) { return 0; }
static inline int xe_display_init(struct xe_device *xe) { return 0; }
static inline void xe_display_register(struct xe_device *xe) {}
static inline void xe_display_unregister(struct xe_device *xe) {}
static inline void xe_display_irq_handler(struct xe_device *xe, u32 master_ctl) {}
static inline void xe_display_irq_enable(struct xe_device *xe, u32 gu_misc_iir) {}
static inline void xe_display_irq_reset(struct xe_device *xe) {}
static inline void xe_display_irq_postinstall(struct xe_device *xe) {}
static inline void xe_display_pm_suspend(struct xe_device *xe) {}
static inline void xe_display_pm_shutdown(struct xe_device *xe) {}
static inline void xe_display_pm_suspend_late(struct xe_device *xe) {}
static inline void xe_display_pm_shutdown_late(struct xe_device *xe) {}
static inline void xe_display_pm_resume_early(struct xe_device *xe) {}
static inline void xe_display_pm_resume(struct xe_device *xe) {}
static inline void xe_display_pm_runtime_suspend(struct xe_device *xe) {}
static inline void xe_display_pm_runtime_suspend_late(struct xe_device *xe) {}
static inline void xe_display_pm_runtime_resume(struct xe_device *xe) {}
#endif /* CONFIG_DRM_XE_DISPLAY */
#endif /* _XE_DISPLAY_H_ */
@@ -0,0 +1,233 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2024 Intel Corporation */
#include <linux/fb.h>
#include <drm/drm_gem.h>
#include <drm/intel/display_parent_interface.h>
#include "intel_fb.h"
#include "xe_bo.h"
#include "xe_display_bo.h"
#include "xe_pxp.h"
#include "xe_ttm_stolen_mgr.h"
#include "xe_wa.h"
#include <generated/xe_device_wa_oob.h>
static bool xe_display_bo_is_protected(struct drm_gem_object *obj)
{
return xe_bo_is_protected(gem_to_xe_bo(obj));
}
static int xe_display_bo_read_from_page(struct drm_gem_object *obj, u64 offset, void *dst, int size)
{
struct xe_bo *bo = gem_to_xe_bo(obj);
return xe_bo_read(bo, offset, dst, size);
}
static int xe_display_bo_framebuffer_init(struct drm_gem_object *obj,
struct drm_mode_fb_cmd2 *mode_cmd)
{
struct xe_bo *bo = gem_to_xe_bo(obj);
struct xe_device *xe = to_xe_device(bo->ttm.base.dev);
int ret;
/*
* Some modifiers require physical alignment of 64KiB VRAM pages;
* require that the BO in those cases is created correctly.
*/
if (XE_IOCTL_DBG(xe, intel_fb_needs_64k_phys(mode_cmd->modifier[0]) &&
!(bo->flags & XE_BO_FLAG_NEEDS_64K)))
return -EINVAL;
xe_bo_get(bo);
ret = ttm_bo_reserve(&bo->ttm, true, false, NULL);
if (ret)
goto err;
if (!(bo->flags & XE_BO_FLAG_FORCE_WC) &&
bo->ttm.type != ttm_bo_type_sg) {
/*
* XE_BO_FLAG_FORCE_WC should ideally be set at creation, or is
* automatically set when creating FB. We cannot change caching
* mode when the bo is VM_BINDed, so we can only set
* coherency with display when unbound.
*/
if (XE_IOCTL_DBG(xe, xe_bo_is_vm_bound(bo))) {
ttm_bo_unreserve(&bo->ttm);
ret = -EINVAL;
goto err;
}
bo->flags |= XE_BO_FLAG_FORCE_WC;
}
ttm_bo_unreserve(&bo->ttm);
return 0;
err:
xe_bo_put(bo);
return ret;
}
static void xe_display_bo_framebuffer_fini(struct drm_gem_object *obj)
{
struct xe_bo *bo = gem_to_xe_bo(obj);
if (bo->flags & XE_BO_FLAG_PINNED) {
/* Unpin our kernel fb first */
xe_bo_lock(bo, false);
xe_bo_unpin(bo);
xe_bo_unlock(bo);
}
xe_bo_put(bo);
}
static struct drm_gem_object *
xe_display_bo_framebuffer_lookup(struct drm_device *drm,
struct drm_file *filp,
const struct drm_mode_fb_cmd2 *mode_cmd)
{
struct xe_device *xe = to_xe_device(drm);
struct xe_bo *bo;
struct drm_gem_object *gem = drm_gem_object_lookup(filp, mode_cmd->handles[0]);
if (!gem)
return ERR_PTR(-ENOENT);
bo = gem_to_xe_bo(gem);
/* Require vram placement or dma-buf import */
if (IS_DGFX(xe) &&
!xe_bo_can_migrate(bo, XE_PL_VRAM0) &&
bo->ttm.type != ttm_bo_type_sg) {
drm_gem_object_put(gem);
return ERR_PTR(-EREMOTE);
}
return gem;
}
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
/*
* FIXME: There shouldn't be any reason to have XE_PAGE_SIZE stride
* alignment. The same 64 as i915 uses should be fine, and we shouldn't need to
* have driver specific values. However, dropping the stride alignment to 64
* leads to underflowing the bo pin count in the atomic cleanup work.
*/
static u32 xe_display_bo_fbdev_pitch_align(u32 stride)
{
return ALIGN(stride, XE_PAGE_SIZE);
}
bool xe_display_bo_fbdev_prefer_stolen(struct xe_device *xe, unsigned int size)
{
struct ttm_resource_manager *stolen;
stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
if (!stolen)
return false;
if (IS_DGFX(xe))
return false;
if (XE_DEVICE_WA(xe, 22019338487_display))
return false;
/*
* If the FB is too big, just don't use it since fbdev is not very
* important and we should probably use that space with FBC or other
* features.
*/
return stolen->size >= (size * 2) >> PAGE_SHIFT;
}
static struct drm_gem_object *xe_display_bo_fbdev_create(struct drm_device *drm, int size)
{
struct xe_device *xe = to_xe_device(drm);
struct xe_bo *obj;
obj = ERR_PTR(-ENODEV);
if (xe_display_bo_fbdev_prefer_stolen(xe, size)) {
obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe),
size,
ttm_bo_type_kernel,
XE_BO_FLAG_FORCE_WC |
XE_BO_FLAG_STOLEN |
XE_BO_FLAG_GGTT,
false);
if (!IS_ERR(obj))
drm_info(&xe->drm, "Allocated fbdev into stolen\n");
else
drm_info(&xe->drm, "Allocated fbdev into stolen failed: %li\n", PTR_ERR(obj));
} else {
drm_info(&xe->drm, "Allocating fbdev: Stolen memory not preferred.\n");
}
if (IS_ERR(obj)) {
obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), size,
ttm_bo_type_kernel,
XE_BO_FLAG_FORCE_WC |
XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) |
XE_BO_FLAG_GGTT,
false);
}
if (IS_ERR(obj)) {
drm_err(&xe->drm, "failed to allocate framebuffer (%pe)\n", obj);
return ERR_PTR(-ENOMEM);
}
return &obj->ttm.base;
}
static void xe_display_bo_fbdev_destroy(struct drm_gem_object *obj)
{
xe_bo_unpin_map_no_vm(gem_to_xe_bo(obj));
}
static int xe_display_bo_fbdev_fill_info(struct drm_gem_object *_obj, struct fb_info *info,
struct i915_vma *vma)
{
struct xe_bo *obj = gem_to_xe_bo(_obj);
struct pci_dev *pdev = to_pci_dev(_obj->dev->dev);
if (!(obj->flags & XE_BO_FLAG_SYSTEM)) {
if (obj->flags & XE_BO_FLAG_STOLEN)
info->fix.smem_start = xe_ttm_stolen_io_offset(obj, 0);
else
info->fix.smem_start =
pci_resource_start(pdev, 2) +
xe_bo_addr(obj, 0, XE_PAGE_SIZE);
info->fix.smem_len = obj->ttm.base.size;
} else {
/* XXX: Pure fiction, as the BO may not be physically accessible.. */
info->fix.smem_start = 0;
info->fix.smem_len = obj->ttm.base.size;
}
XE_WARN_ON(iosys_map_is_null(&obj->vmap));
info->screen_base = obj->vmap.vaddr_iomem;
info->screen_size = obj->ttm.base.size;
return 0;
}
#endif
const struct intel_display_bo_interface xe_display_bo_interface = {
.is_protected = xe_display_bo_is_protected,
.key_check = xe_pxp_obj_key_check,
.fb_mmap = drm_gem_prime_mmap,
.read_from_page = xe_display_bo_read_from_page,
.framebuffer_init = xe_display_bo_framebuffer_init,
.framebuffer_fini = xe_display_bo_framebuffer_fini,
.framebuffer_lookup = xe_display_bo_framebuffer_lookup,
#if IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION)
.fbdev_create = xe_display_bo_fbdev_create,
.fbdev_destroy = xe_display_bo_fbdev_destroy,
.fbdev_fill_info = xe_display_bo_fbdev_fill_info,
.fbdev_pitch_align = xe_display_bo_fbdev_pitch_align,
#endif
};
@@ -0,0 +1,15 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2026 Intel Corporation */
#ifndef __XE_DISPLAY_BO_H__
#define __XE_DISPLAY_BO_H__
#include <linux/types.h>
struct xe_device;
bool xe_display_bo_fbdev_prefer_stolen(struct xe_device *xe, unsigned int size);
extern const struct intel_display_bo_interface xe_display_bo_interface;
#endif
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2026 Intel Corporation */
#include <drm/intel/display_parent_interface.h>
#include "xe_device.h"
#include "xe_pcode.h"
static int xe_display_pcode_read(struct drm_device *drm, u32 mbox, u32 *val, u32 *val1)
{
struct xe_device *xe = to_xe_device(drm);
struct xe_tile *tile = xe_device_get_root_tile(xe);
return xe_pcode_read(tile, mbox, val, val1);
}
static int xe_display_pcode_write_timeout(struct drm_device *drm, u32 mbox, u32 val, int timeout_ms)
{
struct xe_device *xe = to_xe_device(drm);
struct xe_tile *tile = xe_device_get_root_tile(xe);
return xe_pcode_write_timeout(tile, mbox, val, timeout_ms);
}
static int xe_display_pcode_request(struct drm_device *drm, u32 mbox, u32 request,
u32 reply_mask, u32 reply, int timeout_base_ms)
{
struct xe_device *xe = to_xe_device(drm);
struct xe_tile *tile = xe_device_get_root_tile(xe);
return xe_pcode_request(tile, mbox, request, reply_mask, reply, timeout_base_ms);
}
const struct intel_display_pcode_interface xe_display_pcode_interface = {
.read = xe_display_pcode_read,
.write = xe_display_pcode_write_timeout,
.request = xe_display_pcode_request,
};
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2026 Intel Corporation */
#ifndef __XE_DISPLAY_PCODE_H__
#define __XE_DISPLAY_PCODE_H__
extern const struct intel_display_pcode_interface xe_display_pcode_interface;
#endif
@@ -0,0 +1,77 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2025 Intel Corporation */
#include <drm/intel/display_parent_interface.h>
#include "intel_display_core.h"
#include "intel_display_rpm.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_pm.h"
/* -ENOENT means we got the ref, but there's no tracking */
#define INTEL_WAKEREF_DEF ERR_PTR(-ENOENT)
static struct ref_tracker *xe_display_rpm_get(const struct drm_device *drm)
{
return xe_pm_runtime_resume_and_get(to_xe_device(drm)) ? INTEL_WAKEREF_DEF : NULL;
}
static struct ref_tracker *xe_display_rpm_get_if_in_use(const struct drm_device *drm)
{
return xe_pm_runtime_get_if_in_use(to_xe_device(drm)) ? INTEL_WAKEREF_DEF : NULL;
}
static struct ref_tracker *xe_display_rpm_get_noresume(const struct drm_device *drm)
{
xe_pm_runtime_get_noresume(to_xe_device(drm));
return INTEL_WAKEREF_DEF;
}
static void xe_display_rpm_put(const struct drm_device *drm, struct ref_tracker *wakeref)
{
if (wakeref)
xe_pm_runtime_put(to_xe_device(drm));
}
static void xe_display_rpm_put_unchecked(const struct drm_device *drm)
{
xe_pm_runtime_put(to_xe_device(drm));
}
static bool xe_display_rpm_suspended(const struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
return pm_runtime_suspended(xe->drm.dev);
}
static void xe_display_rpm_assert_held(const struct drm_device *drm)
{
/* FIXME */
}
static void xe_display_rpm_assert_block(const struct drm_device *drm)
{
/* FIXME */
}
static void xe_display_rpm_assert_unblock(const struct drm_device *drm)
{
/* FIXME */
}
const struct intel_display_rpm_interface xe_display_rpm_interface = {
.get = xe_display_rpm_get,
.get_raw = xe_display_rpm_get,
.get_if_in_use = xe_display_rpm_get_if_in_use,
.get_noresume = xe_display_rpm_get_noresume,
.put = xe_display_rpm_put,
.put_raw = xe_display_rpm_put,
.put_unchecked = xe_display_rpm_put_unchecked,
.suspended = xe_display_rpm_suspended,
.assert_held = xe_display_rpm_assert_held,
.assert_block = xe_display_rpm_assert_block,
.assert_unblock = xe_display_rpm_assert_unblock
};
@@ -0,0 +1,11 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2025 Intel Corporation
*/
#ifndef _XE_DISPLAY_RPM_H_
#define _XE_DISPLAY_RPM_H_
extern const struct intel_display_rpm_interface xe_display_rpm_interface;
#endif /* _XE_DISPLAY_RPM_H_ */
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2026 Intel Corporation */
#ifndef _XE_DISPLAY_VMA_H_
#define _XE_DISPLAY_VMA_H_
#include <linux/refcount.h>
struct xe_bo;
struct xe_ggtt_node;
struct i915_vma {
refcount_t ref;
struct xe_bo *bo, *dpt;
struct xe_ggtt_node *node;
};
#endif
@@ -0,0 +1,19 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2024 Intel Corporation
*/
#include "intel_display_core.h"
#include "intel_display_wa.h"
#include "xe_device.h"
#include "xe_wa.h"
#include <generated/xe_wa_oob.h>
bool intel_display_needs_wa_16023588340(struct intel_display *display)
{
struct xe_device *xe = to_xe_device(display->drm);
struct xe_gt *wa_gt = xe_root_mmio_gt(xe);
return wa_gt && XE_GT_WA(wa_gt, 16023588340);
}
@@ -0,0 +1,102 @@
// SPDX-License-Identifier: MIT
/*
* Copyright 2023, Intel Corporation.
*/
#include <drm/intel/display_parent_interface.h>
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_dsb_buffer.h"
struct intel_dsb_buffer {
u32 *cmd_buf;
struct xe_bo *bo;
size_t buf_size;
};
static u32 xe_dsb_buffer_ggtt_offset(struct intel_dsb_buffer *dsb_buf)
{
return xe_bo_ggtt_addr(dsb_buf->bo);
}
static void xe_dsb_buffer_write(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val)
{
iosys_map_wr(&dsb_buf->bo->vmap, idx * 4, u32, val);
}
static u32 xe_dsb_buffer_read(struct intel_dsb_buffer *dsb_buf, u32 idx)
{
return iosys_map_rd(&dsb_buf->bo->vmap, idx * 4, u32);
}
static void xe_dsb_buffer_fill(struct intel_dsb_buffer *dsb_buf, u32 idx, u32 val, size_t size)
{
WARN_ON(idx > (dsb_buf->buf_size - size) / sizeof(*dsb_buf->cmd_buf));
iosys_map_memset(&dsb_buf->bo->vmap, idx * 4, val, size);
}
static struct intel_dsb_buffer *xe_dsb_buffer_create(struct drm_device *drm, size_t size)
{
struct xe_device *xe = to_xe_device(drm);
struct intel_dsb_buffer *dsb_buf;
struct xe_bo *obj;
int ret;
dsb_buf = kzalloc_obj(*dsb_buf);
if (!dsb_buf)
return ERR_PTR(-ENOMEM);
/* Set scanout flag for WC mapping */
obj = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe),
PAGE_ALIGN(size),
ttm_bo_type_kernel,
XE_BO_FLAG_VRAM_IF_DGFX(xe_device_get_root_tile(xe)) |
XE_BO_FLAG_FORCE_WC |
XE_BO_FLAG_GGTT,
false);
if (IS_ERR(obj)) {
ret = PTR_ERR(obj);
goto err_pin_map;
}
dsb_buf->bo = obj;
dsb_buf->buf_size = size;
return dsb_buf;
err_pin_map:
kfree(dsb_buf);
return ERR_PTR(ret);
}
static void xe_dsb_buffer_cleanup(struct intel_dsb_buffer *dsb_buf)
{
xe_bo_unpin_map_no_vm(dsb_buf->bo);
kfree(dsb_buf);
}
static void xe_dsb_buffer_flush_map(struct intel_dsb_buffer *dsb_buf)
{
struct xe_device *xe = dsb_buf->bo->tile->xe;
/*
* The memory barrier here is to ensure coherency of DSB vs MMIO,
* both for weak ordering archs and discrete cards.
*/
xe_device_wmb(xe);
xe_device_l2_flush(xe);
}
const struct intel_display_dsb_interface xe_display_dsb_interface = {
.ggtt_offset = xe_dsb_buffer_ggtt_offset,
.write = xe_dsb_buffer_write,
.read = xe_dsb_buffer_read,
.fill = xe_dsb_buffer_fill,
.create = xe_dsb_buffer_create,
.cleanup = xe_dsb_buffer_cleanup,
.flush_map = xe_dsb_buffer_flush_map,
};
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2026 Intel Corporation */
#ifndef __XE_DSB_BUFFER_H__
#define __XE_DSB_BUFFER_H__
extern const struct intel_display_dsb_interface xe_display_dsb_interface;
#endif
@@ -0,0 +1,491 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2021 Intel Corporation
*/
#include <drm/intel/display_parent_interface.h>
#include <drm/ttm/ttm_bo.h>
/* FIXME move the types to parent interface? */
#include "i915_gtt_view_types.h"
/* FIXME move intel_remapped_info_size() & co. to parent interface? */
#include "intel_fb.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_display_vma.h"
#include "xe_fb_pin.h"
#include "xe_ggtt.h"
#include "xe_pat.h"
#include "xe_pm.h"
#include "xe_vram_types.h"
static void
write_dpt_rotated(struct xe_bo *bo, struct iosys_map *map, u32 *dpt_ofs, u32 bo_ofs,
u32 width, u32 height, u32 src_stride, u32 dst_stride)
{
struct xe_device *xe = xe_bo_device(bo);
struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt;
u32 column, row;
u64 pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe_cache_pat_idx(xe, XE_CACHE_NONE));
/* TODO: Maybe rewrite so we can traverse the bo addresses sequentially,
* by writing dpt/ggtt in a different order?
*/
for (column = 0; column < width; column++) {
u32 src_idx = src_stride * (height - 1) + column + bo_ofs;
for (row = 0; row < height; row++) {
u64 addr = xe_bo_addr(bo, src_idx * XE_PAGE_SIZE, XE_PAGE_SIZE);
iosys_map_wr(map, *dpt_ofs, u64, pte | addr);
*dpt_ofs += 8;
src_idx -= src_stride;
}
/* The DE ignores the PTEs for the padding tiles */
*dpt_ofs += (dst_stride - height) * 8;
}
/* Align to next page */
*dpt_ofs = ALIGN(*dpt_ofs, 4096);
}
static unsigned int
write_dpt_padding(struct iosys_map *map, unsigned int dest, unsigned int pad)
{
/* The DE ignores the PTEs for the padding tiles */
return dest + pad * sizeof(u64);
}
static unsigned int
write_dpt_remapped_linear(struct xe_bo *bo, struct iosys_map *map,
unsigned int dest,
const struct intel_remapped_plane_info *plane)
{
struct xe_device *xe = xe_bo_device(bo);
struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt;
const u64 pte = xe_ggtt_encode_pte_flags(ggtt, bo,
xe_cache_pat_idx(xe, XE_CACHE_NONE));
unsigned int offset = plane->offset * XE_PAGE_SIZE;
unsigned int size = plane->size;
while (size--) {
u64 addr = xe_bo_addr(bo, offset, XE_PAGE_SIZE);
iosys_map_wr(map, dest, u64, addr | pte);
dest += sizeof(u64);
offset += XE_PAGE_SIZE;
}
return dest;
}
static unsigned int
write_dpt_remapped_tiled(struct xe_bo *bo, struct iosys_map *map,
unsigned int dest,
const struct intel_remapped_plane_info *plane)
{
struct xe_device *xe = xe_bo_device(bo);
struct xe_ggtt *ggtt = xe_device_get_root_tile(xe)->mem.ggtt;
const u64 pte = xe_ggtt_encode_pte_flags(ggtt, bo,
xe_cache_pat_idx(xe, XE_CACHE_NONE));
unsigned int offset, column, row;
for (row = 0; row < plane->height; row++) {
offset = (plane->offset + plane->src_stride * row) *
XE_PAGE_SIZE;
for (column = 0; column < plane->width; column++) {
u64 addr = xe_bo_addr(bo, offset, XE_PAGE_SIZE);
iosys_map_wr(map, dest, u64, addr | pte);
dest += sizeof(u64);
offset += XE_PAGE_SIZE;
}
dest = write_dpt_padding(map, dest,
plane->dst_stride - plane->width);
}
return dest;
}
static void
write_dpt_remapped(struct xe_bo *bo,
const struct intel_remapped_info *remap_info,
struct iosys_map *map)
{
unsigned int i, dest = 0;
for (i = 0; i < ARRAY_SIZE(remap_info->plane); i++) {
const struct intel_remapped_plane_info *plane =
&remap_info->plane[i];
if (!plane->linear && !plane->width && !plane->height)
continue;
if (dest && remap_info->plane_alignment) {
const unsigned int index = dest / sizeof(u64);
const unsigned int pad =
ALIGN(index, remap_info->plane_alignment) -
index;
dest = write_dpt_padding(map, dest, pad);
}
if (plane->linear)
dest = write_dpt_remapped_linear(bo, map, dest, plane);
else
dest = write_dpt_remapped_tiled(bo, map, dest, plane);
}
}
static int __xe_pin_fb_vma_dpt(struct drm_gem_object *obj,
const struct intel_fb_pin_params *pin_params,
struct i915_vma *vma)
{
struct xe_device *xe = to_xe_device(obj->dev);
struct xe_tile *tile0 = xe_device_get_root_tile(xe);
struct xe_ggtt *ggtt = tile0->mem.ggtt;
const struct i915_gtt_view *view = pin_params->view;
struct xe_bo *bo = gem_to_xe_bo(obj), *dpt;
u32 dpt_size, size = bo->ttm.base.size;
if (view->type == I915_GTT_VIEW_NORMAL)
dpt_size = ALIGN(size / XE_PAGE_SIZE * 8, XE_PAGE_SIZE);
else if (view->type == I915_GTT_VIEW_REMAPPED)
dpt_size = ALIGN(intel_remapped_info_size(&view->remapped) * 8,
XE_PAGE_SIZE);
else
/* display uses 4K tiles instead of bytes here, convert to entries.. */
dpt_size = ALIGN(intel_rotation_info_size(&view->rotated) * 8,
XE_PAGE_SIZE);
dpt = xe_bo_create_pin_map_at_novm(xe, tile0,
dpt_size, ~0ull,
ttm_bo_type_kernel,
XE_BO_FLAG_VRAM_IF_DGFX(tile0) |
XE_BO_FLAG_GGTT |
XE_BO_FLAG_PAGETABLE |
XE_BO_FLAG_FORCE_WC,
pin_params->alignment, false);
if (IS_ERR(dpt))
return PTR_ERR(dpt);
if (view->type == I915_GTT_VIEW_NORMAL) {
u64 pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe_cache_pat_idx(xe, XE_CACHE_NONE));
u32 x;
for (x = 0; x < size / XE_PAGE_SIZE; x++) {
u64 addr = xe_bo_addr(bo, x * XE_PAGE_SIZE, XE_PAGE_SIZE);
iosys_map_wr(&dpt->vmap, x * 8, u64, pte | addr);
}
} else if (view->type == I915_GTT_VIEW_REMAPPED) {
write_dpt_remapped(bo, &view->remapped, &dpt->vmap);
} else {
const struct intel_rotation_info *rot_info = &view->rotated;
u32 i, dpt_ofs = 0;
for (i = 0; i < ARRAY_SIZE(rot_info->plane); i++)
write_dpt_rotated(bo, &dpt->vmap, &dpt_ofs,
rot_info->plane[i].offset,
rot_info->plane[i].width,
rot_info->plane[i].height,
rot_info->plane[i].src_stride,
rot_info->plane[i].dst_stride);
}
vma->dpt = dpt;
vma->node = dpt->ggtt_node[tile0->id];
/* Ensure DPT writes are flushed */
xe_device_l2_flush(xe);
return 0;
}
static void
write_ggtt_rotated(struct xe_ggtt *ggtt, u32 *ggtt_ofs,
u64 pte_flags,
xe_ggtt_set_pte_fn write_pte,
struct xe_bo *bo, u32 bo_ofs,
u32 width, u32 height, u32 src_stride, u32 dst_stride)
{
u32 column, row;
for (column = 0; column < width; column++) {
u32 src_idx = src_stride * (height - 1) + column + bo_ofs;
for (row = 0; row < height; row++) {
u64 addr = xe_bo_addr(bo, src_idx * XE_PAGE_SIZE, XE_PAGE_SIZE);
write_pte(ggtt, *ggtt_ofs, pte_flags | addr);
*ggtt_ofs += XE_PAGE_SIZE;
src_idx -= src_stride;
}
/* The DE ignores the PTEs for the padding tiles */
*ggtt_ofs += (dst_stride - height) * XE_PAGE_SIZE;
}
}
struct fb_rotate_args {
const struct i915_gtt_view *view;
struct xe_bo *bo;
};
static void write_ggtt_rotated_node(struct xe_ggtt *ggtt, struct xe_ggtt_node *node,
u64 pte_flags, xe_ggtt_set_pte_fn write_pte, void *data)
{
struct fb_rotate_args *args = data;
struct xe_bo *bo = args->bo;
const struct intel_rotation_info *rot_info = &args->view->rotated;
u32 ggtt_ofs = xe_ggtt_node_addr(node);
for (u32 i = 0; i < ARRAY_SIZE(rot_info->plane); i++)
write_ggtt_rotated(ggtt, &ggtt_ofs, pte_flags, write_pte,
bo, rot_info->plane[i].offset,
rot_info->plane[i].width,
rot_info->plane[i].height,
rot_info->plane[i].src_stride,
rot_info->plane[i].dst_stride);
}
static int __xe_pin_fb_vma_ggtt(struct drm_gem_object *obj,
const struct intel_fb_pin_params *pin_params,
struct i915_vma *vma)
{
const struct i915_gtt_view *view = pin_params->view;
struct xe_bo *bo = gem_to_xe_bo(obj);
struct xe_device *xe = to_xe_device(obj->dev);
struct xe_tile *tile0 = xe_device_get_root_tile(xe);
struct xe_ggtt *ggtt = tile0->mem.ggtt;
u64 pte, size;
u32 align;
int ret = 0;
/* TODO: Consider sharing framebuffer mapping?
* embed i915_vma inside intel_framebuffer
*/
guard(xe_pm_runtime_noresume)(xe);
align = max(XE_PAGE_SIZE, pin_params->alignment);
if (xe_bo_is_vram(bo) && xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K)
align = max(align, SZ_64K);
/* Fast case, preallocated GGTT view? */
if (bo->ggtt_node[tile0->id] && view->type == I915_GTT_VIEW_NORMAL) {
vma->node = bo->ggtt_node[tile0->id];
return 0;
}
/* TODO: Consider sharing framebuffer mapping?
* embed i915_vma inside intel_framebuffer
*/
if (view->type == I915_GTT_VIEW_NORMAL)
size = xe_bo_size(bo);
else
/* display uses tiles instead of bytes here, so convert it back.. */
size = intel_rotation_info_size(&view->rotated) * XE_PAGE_SIZE;
pte = xe_ggtt_encode_pte_flags(ggtt, bo, xe_cache_pat_idx(xe, XE_CACHE_NONE));
vma->node = xe_ggtt_insert_node_transform(ggtt, bo, pte,
ALIGN(size, align), align,
view->type == I915_GTT_VIEW_NORMAL ?
NULL : write_ggtt_rotated_node,
&(struct fb_rotate_args){view, bo});
if (IS_ERR(vma->node))
ret = PTR_ERR(vma->node);
return ret;
}
static struct i915_vma *__xe_pin_fb_vma(struct drm_gem_object *obj, bool is_dpt,
const struct intel_fb_pin_params *pin_params)
{
struct xe_device *xe = to_xe_device(obj->dev);
struct i915_vma *vma = kzalloc(sizeof(*vma), GFP_KERNEL);
struct xe_bo *bo = gem_to_xe_bo(obj);
struct xe_validation_ctx ctx;
struct drm_exec exec;
int ret = 0;
/* We reject creating !SCANOUT fb's, so this is weird.. */
drm_WARN_ON(bo->ttm.base.dev, !(bo->flags & XE_BO_FLAG_FORCE_WC) &&
bo->ttm.type != ttm_bo_type_sg);
if (!vma)
return ERR_PTR(-ENODEV);
refcount_set(&vma->ref, 1);
if (IS_DGFX(to_xe_device(bo->ttm.base.dev)) &&
pin_params->needs_cpu_lmem_access &&
!(bo->flags & XE_BO_FLAG_NEEDS_CPU_ACCESS)) {
struct xe_vram_region *vram = xe_device_get_root_tile(xe)->mem.vram;
/*
* If we need to able to access the clear-color value stored in
* the buffer, then we require that such buffers are also CPU
* accessible. This is important on small-bar systems where
* only some subset of VRAM is CPU accessible.
*/
if (xe_vram_region_io_size(vram) < xe_vram_region_usable_size(vram)) {
ret = -EINVAL;
goto err;
}
}
/*
* Pin the framebuffer, we can't use xe_bo_(un)pin functions as the
* assumptions are incorrect for framebuffers
*/
xe_validation_guard(&ctx, &xe->val, &exec, (struct xe_val_flags) {.interruptible = true},
ret) {
ret = drm_exec_lock_obj(&exec, &bo->ttm.base);
drm_exec_retry_on_contention(&exec);
if (ret)
break;
if (IS_DGFX(xe))
ret = xe_bo_migrate(bo, XE_PL_VRAM0, NULL, &exec);
else
ret = xe_bo_validate(bo, NULL, true, &exec);
drm_exec_retry_on_contention(&exec);
xe_validation_retry_on_oom(&ctx, &ret);
if (!ret)
ttm_bo_pin(&bo->ttm);
}
if (ret)
goto err;
vma->bo = bo;
if (is_dpt)
ret = __xe_pin_fb_vma_dpt(obj, pin_params, vma);
else
ret = __xe_pin_fb_vma_ggtt(obj, pin_params, vma);
if (ret)
goto err_unpin;
return vma;
err_unpin:
ttm_bo_reserve(&bo->ttm, false, false, NULL);
ttm_bo_unpin(&bo->ttm);
ttm_bo_unreserve(&bo->ttm);
err:
kfree(vma);
return ERR_PTR(ret);
}
static void __xe_unpin_fb_vma(struct i915_vma *vma)
{
u8 tile_id = xe_device_get_root_tile(xe_bo_device(vma->bo))->id;
if (!refcount_dec_and_test(&vma->ref))
return;
if (vma->dpt)
xe_bo_unpin_map_no_vm(vma->dpt);
else if (vma->bo->ggtt_node[tile_id] != vma->node)
xe_ggtt_node_remove(vma->node, false);
ttm_bo_reserve(&vma->bo->ttm, false, false, NULL);
ttm_bo_unpin(&vma->bo->ttm);
ttm_bo_unreserve(&vma->bo->ttm);
kfree(vma);
}
int xe_fb_pin_ggtt_pin(struct drm_gem_object *obj,
const struct intel_fb_pin_params *pin_params,
struct i915_vma **out_ggtt_vma,
u32 *out_offset,
int *out_fence_id)
{
struct i915_vma *ggtt_vma;
ggtt_vma = __xe_pin_fb_vma(obj, false, pin_params);
if (IS_ERR(ggtt_vma))
return PTR_ERR(ggtt_vma);
*out_ggtt_vma = ggtt_vma;
*out_offset = xe_ggtt_node_addr(ggtt_vma->node);
if (out_fence_id)
*out_fence_id = -1;
return 0;
}
static void xe_fb_pin_ggtt_unpin(struct i915_vma *ggtt_vma,
int fence_id)
{
WARN_ON(fence_id >= 0);
__xe_unpin_fb_vma(ggtt_vma);
}
static int xe_fb_pin_dpt_pin(struct drm_gem_object *obj, struct intel_dpt *dpt,
const struct intel_fb_pin_params *pin_params,
struct i915_vma **out_dpt_vma,
struct i915_vma **out_ggtt_vma,
u32 *out_offset)
{
struct i915_vma *ggtt_vma;
WARN_ON(dpt);
ggtt_vma = __xe_pin_fb_vma(obj, true, pin_params);
if (IS_ERR(ggtt_vma))
return PTR_ERR(ggtt_vma);
*out_dpt_vma = NULL; /* not used on xe */
*out_ggtt_vma = ggtt_vma;
*out_offset = xe_ggtt_node_addr(ggtt_vma->node);
return 0;
}
static void xe_fb_pin_dpt_unpin(struct intel_dpt *dpt,
struct i915_vma *dpt_vma,
struct i915_vma *ggtt_vma)
{
WARN_ON(dpt || dpt_vma);
__xe_unpin_fb_vma(ggtt_vma);
}
static struct i915_vma *
xe_fb_pin_reuse_vma(struct i915_vma *old_ggtt_vma,
struct drm_gem_object *old_obj,
const struct i915_gtt_view *old_view,
struct drm_gem_object *new_obj,
const struct i915_gtt_view *new_view,
u32 *out_offset)
{
if (old_ggtt_vma && old_obj == new_obj &&
!memcmp(old_view, new_view, sizeof(*new_view))) {
refcount_inc(&old_ggtt_vma->ref);
*out_offset = xe_ggtt_node_addr(old_ggtt_vma->node);
return old_ggtt_vma;
}
return NULL;
}
static void xe_fb_pin_get_map(struct i915_vma *vma, struct iosys_map *map)
{
*map = vma->bo->vmap;
}
const struct intel_display_fb_pin_interface xe_display_fb_pin_interface = {
.ggtt_pin = xe_fb_pin_ggtt_pin,
.ggtt_unpin = xe_fb_pin_ggtt_unpin,
.dpt_pin = xe_fb_pin_dpt_pin,
.dpt_unpin = xe_fb_pin_dpt_unpin,
.reuse_vma = xe_fb_pin_reuse_vma,
.get_map = xe_fb_pin_get_map,
};
@@ -0,0 +1,21 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2026 Intel Corporation */
#ifndef __XE_FB_PIN_H__
#define __XE_FB_PIN_H__
#include <linux/types.h>
struct drm_gem_object;
struct i915_vma;
struct intel_fb_pin_params;
int xe_fb_pin_ggtt_pin(struct drm_gem_object *obj,
const struct intel_fb_pin_params *pin_params,
struct i915_vma **out_ggtt_vma,
u32 *out_offset,
int *out_fence_id);
extern const struct intel_display_fb_pin_interface xe_display_fb_pin_interface;
#endif /* __XE_FB_PIN_H__ */
@@ -0,0 +1,71 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2026 Intel Corporation */
#include <drm/drm_gem.h>
#include <drm/intel/display_parent_interface.h>
#include "intel_frontbuffer.h"
#include "xe_frontbuffer.h"
struct xe_frontbuffer {
struct intel_frontbuffer base;
struct drm_gem_object *obj;
struct kref ref;
};
static struct intel_frontbuffer *xe_frontbuffer_get(struct drm_gem_object *obj)
{
struct xe_frontbuffer *front;
front = kmalloc_obj(*front);
if (!front)
return NULL;
intel_frontbuffer_init(&front->base, obj->dev);
kref_init(&front->ref);
drm_gem_object_get(obj);
front->obj = obj;
return &front->base;
}
static void xe_frontbuffer_ref(struct intel_frontbuffer *_front)
{
struct xe_frontbuffer *front =
container_of(_front, typeof(*front), base);
kref_get(&front->ref);
}
static void frontbuffer_release(struct kref *ref)
{
struct xe_frontbuffer *front =
container_of(ref, typeof(*front), ref);
intel_frontbuffer_fini(&front->base);
drm_gem_object_put(front->obj);
kfree(front);
}
static void xe_frontbuffer_put(struct intel_frontbuffer *_front)
{
struct xe_frontbuffer *front =
container_of(_front, typeof(*front), base);
kref_put(&front->ref, frontbuffer_release);
}
static void xe_frontbuffer_flush_for_display(struct intel_frontbuffer *front)
{
}
const struct intel_display_frontbuffer_interface xe_display_frontbuffer_interface = {
.get = xe_frontbuffer_get,
.ref = xe_frontbuffer_ref,
.put = xe_frontbuffer_put,
.flush_for_display = xe_frontbuffer_flush_for_display,
};
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2026 Intel Corporation */
#ifndef _XE_FRONTBUFFER_H_
#define _XE_FRONTBUFFER_H_
extern const struct intel_display_frontbuffer_interface xe_display_frontbuffer_interface;
#endif
@@ -0,0 +1,217 @@
// SPDX-License-Identifier: MIT
/*
* Copyright 2023, Intel Corporation.
*/
#include <linux/delay.h>
#include <drm/drm_print.h>
#include <drm/intel/display_parent_interface.h>
#include <drm/intel/i915_hdcp_interface.h>
#include "abi/gsc_command_header_abi.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_force_wake.h"
#include "xe_gsc_proxy.h"
#include "xe_gsc_submit.h"
#include "xe_hdcp_gsc.h"
#include "xe_map.h"
#include "xe_pm.h"
#include "xe_uc_fw.h"
#define HECI_MEADDRESS_HDCP 18
struct intel_hdcp_gsc_context {
struct xe_device *xe;
struct xe_bo *hdcp_bo;
u64 hdcp_cmd_in;
u64 hdcp_cmd_out;
};
#define HDCP_GSC_HEADER_SIZE sizeof(struct intel_gsc_mtl_header)
static bool intel_hdcp_gsc_check_status(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
struct xe_tile *tile = xe_device_get_root_tile(xe);
struct xe_gt *gt = tile->media_gt;
struct xe_gsc *gsc;
if (!gt) {
drm_dbg_kms(&xe->drm,
"not checking GSC status for HDCP2.x: media GT not present or disabled\n");
return false;
}
gsc = &gt->uc.gsc;
if (!xe_uc_fw_is_available(&gsc->fw)) {
drm_dbg_kms(&xe->drm,
"GSC Components not ready for HDCP2.x\n");
return false;
}
guard(xe_pm_runtime)(xe);
CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC);
if (!fw_ref.domains) {
drm_dbg_kms(&xe->drm,
"failed to get forcewake to check proxy status\n");
return false;
}
return xe_gsc_proxy_init_done(gsc);
}
/*This function helps allocate memory for the command that we will send to gsc cs */
static int intel_hdcp_gsc_initialize_message(struct xe_device *xe,
struct intel_hdcp_gsc_context *gsc_context)
{
struct xe_bo *bo = NULL;
u64 cmd_in, cmd_out;
int ret = 0;
/* allocate object of two page for HDCP command memory and store it */
bo = xe_bo_create_pin_map_novm(xe, xe_device_get_root_tile(xe), PAGE_SIZE * 2,
ttm_bo_type_kernel,
XE_BO_FLAG_SYSTEM |
XE_BO_FLAG_GGTT, false);
if (IS_ERR(bo)) {
drm_err(&xe->drm, "Failed to allocate bo for HDCP streaming command!\n");
ret = PTR_ERR(bo);
goto out;
}
cmd_in = xe_bo_ggtt_addr(bo);
cmd_out = cmd_in + PAGE_SIZE;
xe_map_memset(xe, &bo->vmap, 0, 0, xe_bo_size(bo));
gsc_context->hdcp_bo = bo;
gsc_context->hdcp_cmd_in = cmd_in;
gsc_context->hdcp_cmd_out = cmd_out;
gsc_context->xe = xe;
out:
return ret;
}
static struct intel_hdcp_gsc_context *intel_hdcp_gsc_context_alloc(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
struct intel_hdcp_gsc_context *gsc_context;
int ret;
gsc_context = kzalloc_obj(*gsc_context);
if (!gsc_context)
return ERR_PTR(-ENOMEM);
/*
* NOTE: No need to lock the comp mutex here as it is already
* going to be taken before this function called
*/
ret = intel_hdcp_gsc_initialize_message(xe, gsc_context);
if (ret) {
drm_err(&xe->drm, "Could not initialize gsc_context\n");
kfree(gsc_context);
gsc_context = ERR_PTR(ret);
}
return gsc_context;
}
static void intel_hdcp_gsc_context_free(struct intel_hdcp_gsc_context *gsc_context)
{
if (!gsc_context)
return;
xe_bo_unpin_map_no_vm(gsc_context->hdcp_bo);
kfree(gsc_context);
}
static int xe_gsc_send_sync(struct xe_device *xe,
struct intel_hdcp_gsc_context *gsc_context,
u32 msg_size_in, u32 msg_size_out,
u32 addr_out_off)
{
struct xe_gt *gt = gsc_context->hdcp_bo->tile->media_gt;
struct iosys_map *map = &gsc_context->hdcp_bo->vmap;
struct xe_gsc *gsc = &gt->uc.gsc;
int ret;
ret = xe_gsc_pkt_submit_kernel(gsc, gsc_context->hdcp_cmd_in, msg_size_in,
gsc_context->hdcp_cmd_out, msg_size_out);
if (ret) {
drm_err(&xe->drm, "failed to send gsc HDCP msg (%d)\n", ret);
return ret;
}
if (xe_gsc_check_and_update_pending(xe, map, 0, map, addr_out_off))
return -EAGAIN;
ret = xe_gsc_read_out_header(xe, map, addr_out_off,
sizeof(struct hdcp_cmd_header), NULL);
return ret;
}
static ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_context,
void *msg_in, size_t msg_in_len,
void *msg_out, size_t msg_out_len)
{
struct xe_device *xe = gsc_context->xe;
const size_t max_msg_size = PAGE_SIZE - HDCP_GSC_HEADER_SIZE;
u64 host_session_id;
u32 msg_size_in, msg_size_out;
u32 addr_out_off, addr_in_wr_off = 0;
int ret, tries = 0;
if (msg_in_len > max_msg_size || msg_out_len > max_msg_size)
return -ENOSPC;
msg_size_in = msg_in_len + HDCP_GSC_HEADER_SIZE;
msg_size_out = msg_out_len + HDCP_GSC_HEADER_SIZE;
addr_out_off = PAGE_SIZE;
host_session_id = xe_gsc_create_host_session_id();
guard(xe_pm_runtime_noresume)(xe);
addr_in_wr_off = xe_gsc_emit_header(xe, &gsc_context->hdcp_bo->vmap,
addr_in_wr_off, HECI_MEADDRESS_HDCP,
host_session_id, msg_in_len);
xe_map_memcpy_to(xe, &gsc_context->hdcp_bo->vmap, addr_in_wr_off,
msg_in, msg_in_len);
/*
* Keep sending request in case the pending bit is set no need to add
* message handle as we are using same address hence loc. of header is
* same and it will contain the message handle. we will send the message
* 20 times each message 50 ms apart
*/
do {
ret = xe_gsc_send_sync(xe, gsc_context, msg_size_in, msg_size_out,
addr_out_off);
/* Only try again if gsc says so */
if (ret != -EAGAIN)
break;
msleep(50);
} while (++tries < 20);
if (ret)
return ret;
xe_map_memcpy_from(xe, msg_out, &gsc_context->hdcp_bo->vmap,
addr_out_off + HDCP_GSC_HEADER_SIZE,
msg_out_len);
return ret;
}
const struct intel_display_hdcp_interface xe_display_hdcp_interface = {
.gsc_msg_send = intel_hdcp_gsc_msg_send,
.gsc_check_status = intel_hdcp_gsc_check_status,
.gsc_context_alloc = intel_hdcp_gsc_context_alloc,
.gsc_context_free = intel_hdcp_gsc_context_free,
};
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __XE_HDCP_GSC_H__
#define __XE_HDCP_GSC_H__
extern const struct intel_display_hdcp_interface xe_display_hdcp_interface;
#endif
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2021 Intel Corporation
*/
#include <drm/intel/display_parent_interface.h>
#include "regs/xe_gtt_defs.h"
/* FIXME move intel_remapped_info_size() & co. */
#include "intel_fb.h"
/* FIXME move intel_initial_plane_config */
#include "intel_display_types.h"
#include "xe_bo.h"
#include "xe_display_bo.h"
#include "xe_display_vma.h"
#include "xe_fb_pin.h"
#include "xe_ggtt.h"
#include "xe_mmio.h"
#include "xe_vram_types.h"
static struct xe_bo *
initial_plane_bo(struct xe_device *xe,
struct intel_initial_plane_config *plane_config)
{
struct xe_tile *tile0 = xe_device_get_root_tile(xe);
struct xe_bo *bo;
resource_size_t phys_base;
u32 base, size, flags;
u64 page_size = xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K ? SZ_64K : SZ_4K;
if (plane_config->size == 0)
return NULL;
flags = XE_BO_FLAG_FORCE_WC | XE_BO_FLAG_GGTT;
base = round_down(plane_config->base, page_size);
if (IS_DGFX(xe)) {
u64 pte = xe_ggtt_read_pte(tile0->mem.ggtt, base);
if (!(pte & XE_GGTT_PTE_DM)) {
drm_err(&xe->drm,
"Initial plane programming missing DM bit\n");
return NULL;
}
phys_base = pte & ~(page_size - 1);
flags |= XE_BO_FLAG_VRAM0;
/*
* We don't currently expect this to ever be placed in the
* stolen portion.
*/
if (phys_base >= xe_vram_region_usable_size(tile0->mem.vram)) {
drm_err(&xe->drm,
"Initial plane programming using invalid range, phys_base=%pa\n",
&phys_base);
return NULL;
}
drm_dbg(&xe->drm,
"Using phys_base=%pa, based on initial plane programming\n",
&phys_base);
} else {
struct ttm_resource_manager *stolen = ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
if (!stolen)
return NULL;
phys_base = base;
flags |= XE_BO_FLAG_STOLEN;
if (IS_ENABLED(CONFIG_FRAMEBUFFER_CONSOLE) &&
IS_ENABLED(CONFIG_DRM_FBDEV_EMULATION) &&
!xe_display_bo_fbdev_prefer_stolen(xe, plane_config->size)) {
drm_info(&xe->drm, "Initial FB size exceeds half of stolen, discarding\n");
return NULL;
}
}
size = round_up(plane_config->base + plane_config->size,
page_size);
size -= base;
bo = xe_bo_create_pin_map_at_novm(xe, tile0, size, phys_base,
ttm_bo_type_kernel, flags, 0, false);
if (IS_ERR(bo)) {
drm_dbg(&xe->drm,
"Failed to create bo phys_base=%pa size %u with flags %x: %li\n",
&phys_base, size, flags, PTR_ERR(bo));
return NULL;
}
return bo;
}
static struct drm_gem_object *
xe_alloc_initial_plane_obj(struct drm_device *drm,
struct intel_initial_plane_config *plane_config)
{
struct xe_device *xe = to_xe_device(drm);
struct drm_mode_fb_cmd2 mode_cmd = { 0 };
struct drm_framebuffer *fb = plane_config->fb;
struct xe_bo *bo;
mode_cmd.pixel_format = fb->format->format;
mode_cmd.width = fb->width;
mode_cmd.height = fb->height;
mode_cmd.pitches[0] = fb->pitches[0];
mode_cmd.modifier[0] = fb->modifier;
mode_cmd.flags = DRM_MODE_FB_MODIFIERS;
bo = initial_plane_bo(xe, plane_config);
if (!bo)
return NULL;
if (intel_framebuffer_init(to_intel_framebuffer(fb),
&bo->ttm.base, fb->format, &mode_cmd)) {
drm_dbg_kms(&xe->drm, "intel fb init failed\n");
goto err_bo;
}
/* Reference handed over to fb */
xe_bo_put(bo);
return &bo->ttm.base;
err_bo:
xe_bo_unpin_map_no_vm(bo);
return NULL;
}
static int
xe_initial_plane_setup(struct drm_plane_state *_plane_state,
struct intel_initial_plane_config *plane_config,
struct drm_framebuffer *fb,
struct i915_vma *_unused)
{
struct intel_plane_state *plane_state = to_intel_plane_state(_plane_state);
struct i915_vma *vma;
struct intel_fb_pin_params pin_params = {
.view = &plane_state->view.gtt,
};
u32 offset;
int ret;
ret = xe_fb_pin_ggtt_pin(intel_fb_bo(fb), &pin_params, &vma, &offset, NULL);
if (ret)
return ret;
plane_state->ggtt_vma = vma;
plane_state->surf = offset;
plane_config->vma = vma;
return 0;
}
static void xe_plane_config_fini(struct intel_initial_plane_config *plane_config)
{
}
const struct intel_display_initial_plane_interface xe_display_initial_plane_interface = {
.alloc_obj = xe_alloc_initial_plane_obj,
.setup = xe_initial_plane_setup,
.config_fini = xe_plane_config_fini,
};
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __XE_INITIAL_PLANE_H__
#define __XE_INITIAL_PLANE_H__
extern const struct intel_display_initial_plane_interface xe_display_initial_plane_interface;
#endif
@@ -0,0 +1,104 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2025 Intel Corporation */
#include <drm/drm_cache.h>
#include <drm/drm_panic.h>
#include <drm/intel/display_parent_interface.h>
#include "intel_display_types.h"
#include "intel_fb.h"
#include "xe_bo.h"
#include "xe_panic.h"
#include "xe_res_cursor.h"
struct intel_panic {
struct xe_res_cursor res;
struct iosys_map vmap;
int page;
};
static void xe_panic_kunmap(struct intel_panic *panic)
{
if (!panic->vmap.is_iomem && iosys_map_is_set(&panic->vmap)) {
drm_clflush_virt_range(panic->vmap.vaddr, PAGE_SIZE);
kunmap_local(panic->vmap.vaddr);
}
iosys_map_clear(&panic->vmap);
panic->page = -1;
}
/*
* The scanout buffer pages are not mapped, so for each pixel,
* use kmap_local_page_try_from_panic() to map the page, and write the pixel.
* Try to keep the map from the previous pixel, to avoid too much map/unmap.
*/
static void xe_panic_page_set_pixel(struct drm_scanout_buffer *sb, unsigned int x,
unsigned int y, u32 color)
{
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
struct intel_panic *panic = fb->panic;
struct xe_bo *bo = gem_to_xe_bo(intel_fb_bo(&fb->base));
unsigned int new_page;
unsigned int offset;
if (fb->panic_tiling)
offset = fb->panic_tiling(sb->width, x, y);
else
offset = y * sb->pitch[0] + x * sb->format->cpp[0];
new_page = offset >> PAGE_SHIFT;
offset = offset % PAGE_SIZE;
if (new_page != panic->page) {
if (xe_bo_is_vram(bo)) {
/* Display is always mapped on root tile */
struct xe_vram_region *vram = xe_bo_device(bo)->mem.vram;
if (panic->page < 0 || new_page < panic->page) {
xe_res_first(bo->ttm.resource, new_page * PAGE_SIZE,
bo->ttm.base.size - new_page * PAGE_SIZE, &panic->res);
} else {
xe_res_next(&panic->res, PAGE_SIZE * (new_page - panic->page));
}
iosys_map_set_vaddr_iomem(&panic->vmap,
vram->mapping + panic->res.start);
} else {
xe_panic_kunmap(panic);
iosys_map_set_vaddr(&panic->vmap,
ttm_bo_kmap_try_from_panic(&bo->ttm,
new_page));
}
panic->page = new_page;
}
if (iosys_map_is_set(&panic->vmap))
iosys_map_wr(&panic->vmap, offset, u32, color);
}
static struct intel_panic *xe_panic_alloc(void)
{
struct intel_panic *panic;
panic = kzalloc_obj(*panic);
return panic;
}
static int xe_panic_setup(struct intel_panic *panic, struct drm_scanout_buffer *sb)
{
struct intel_framebuffer *fb = (struct intel_framebuffer *)sb->private;
struct xe_bo *bo = gem_to_xe_bo(intel_fb_bo(&fb->base));
if (xe_bo_is_vram(bo) && !xe_bo_is_visible_vram(bo))
return -ENODEV;
panic->page = -1;
sb->set_pixel = xe_panic_page_set_pixel;
return 0;
}
const struct intel_display_panic_interface xe_display_panic_interface = {
.alloc = xe_panic_alloc,
.setup = xe_panic_setup,
.finish = xe_panic_kunmap,
};
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __XE_PANIC_H__
#define __XE_PANIC_H__
extern const struct intel_display_panic_interface xe_display_panic_interface;
#endif
@@ -0,0 +1,113 @@
// SPDX-License-Identifier: MIT
/* Copyright © 2025 Intel Corporation */
#include <drm/intel/display_parent_interface.h>
#include "xe_res_cursor.h"
#include "xe_stolen.h"
#include "xe_ttm_stolen_mgr.h"
#include "xe_validation.h"
struct intel_stolen_node {
struct xe_device *xe;
struct xe_bo *bo;
};
static int xe_stolen_insert_node_in_range(struct intel_stolen_node *node, u64 size,
unsigned int align, u64 start, u64 end)
{
struct xe_device *xe = node->xe;
struct xe_bo *bo;
int err = 0;
u32 flags = XE_BO_FLAG_PINNED | XE_BO_FLAG_STOLEN;
if (start < SZ_4K)
start = SZ_4K;
if (align) {
size = ALIGN(size, align);
start = ALIGN(start, align);
}
bo = xe_bo_create_pin_range_novm(xe, xe_device_get_root_tile(xe),
size, start, end, ttm_bo_type_kernel, flags);
if (IS_ERR(bo)) {
err = PTR_ERR(bo);
bo = NULL;
return err;
}
node->bo = bo;
return err;
}
static void xe_stolen_remove_node(struct intel_stolen_node *node)
{
xe_bo_unpin_map_no_vm(node->bo);
node->bo = NULL;
}
static bool xe_stolen_initialized(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
return ttm_manager_type(&xe->ttm, XE_PL_STOLEN);
}
static bool xe_stolen_node_allocated(const struct intel_stolen_node *node)
{
return node->bo;
}
static u64 xe_stolen_node_offset(const struct intel_stolen_node *node)
{
struct xe_res_cursor res;
xe_res_first(node->bo->ttm.resource, 0, 4096, &res);
return res.start;
}
static u64 xe_stolen_node_address(const struct intel_stolen_node *node)
{
struct xe_device *xe = node->xe;
return xe_ttm_stolen_gpu_offset(xe) + xe_stolen_node_offset(node);
}
static u64 xe_stolen_node_size(const struct intel_stolen_node *node)
{
return xe_bo_size(node->bo);
}
static struct intel_stolen_node *xe_stolen_node_alloc(struct drm_device *drm)
{
struct xe_device *xe = to_xe_device(drm);
struct intel_stolen_node *node;
node = kzalloc_obj(*node);
if (!node)
return NULL;
node->xe = xe;
return node;
}
static void xe_stolen_node_free(const struct intel_stolen_node *node)
{
kfree(node);
}
const struct intel_display_stolen_interface xe_display_stolen_interface = {
.insert_node_in_range = xe_stolen_insert_node_in_range,
.remove_node = xe_stolen_remove_node,
.initialized = xe_stolen_initialized,
.node_allocated = xe_stolen_node_allocated,
.node_offset = xe_stolen_node_offset,
.node_address = xe_stolen_node_address,
.node_size = xe_stolen_node_size,
.node_alloc = xe_stolen_node_alloc,
.node_free = xe_stolen_node_free,
};
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: MIT */
/* Copyright © 2025 Intel Corporation */
#ifndef __XE_STOLEN_H__
#define __XE_STOLEN_H__
extern const struct intel_display_stolen_interface xe_display_stolen_interface;
#endif
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: MIT
/*
* Copyright © 2024 Intel Corporation
*/
#include "intel_display_core.h"
#include "intel_tdf.h"
#include "xe_device.h"
void intel_td_flush(struct intel_display *display)
{
struct xe_device *xe = to_xe_device(display->drm);
xe_device_td_flush(xe);
}
@@ -0,0 +1,79 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2025 Intel Corporation
*/
#ifndef _XE_ALU_COMMANDS_H_
#define _XE_ALU_COMMANDS_H_
#include "instructions/xe_instr_defs.h"
/* Instruction Opcodes */
#define CS_ALU_OPCODE_NOOP 0x000
#define CS_ALU_OPCODE_FENCE_RD 0x001
#define CS_ALU_OPCODE_FENCE_WR 0x002
#define CS_ALU_OPCODE_LOAD 0x080
#define CS_ALU_OPCODE_LOADINV 0x480
#define CS_ALU_OPCODE_LOAD0 0x081
#define CS_ALU_OPCODE_LOAD1 0x481
#define CS_ALU_OPCODE_LOADIND 0x082
#define CS_ALU_OPCODE_ADD 0x100
#define CS_ALU_OPCODE_SUB 0x101
#define CS_ALU_OPCODE_AND 0x102
#define CS_ALU_OPCODE_OR 0x103
#define CS_ALU_OPCODE_XOR 0x104
#define CS_ALU_OPCODE_SHL 0x105
#define CS_ALU_OPCODE_SHR 0x106
#define CS_ALU_OPCODE_SAR 0x107
#define CS_ALU_OPCODE_STORE 0x180
#define CS_ALU_OPCODE_STOREINV 0x580
#define CS_ALU_OPCODE_STOREIND 0x181
/* Instruction Operands */
#define CS_ALU_OPERAND_REG(n) REG_FIELD_PREP(GENMASK(3, 0), (n))
#define CS_ALU_OPERAND_REG0 0x0
#define CS_ALU_OPERAND_REG1 0x1
#define CS_ALU_OPERAND_REG2 0x2
#define CS_ALU_OPERAND_REG3 0x3
#define CS_ALU_OPERAND_REG4 0x4
#define CS_ALU_OPERAND_REG5 0x5
#define CS_ALU_OPERAND_REG6 0x6
#define CS_ALU_OPERAND_REG7 0x7
#define CS_ALU_OPERAND_REG8 0x8
#define CS_ALU_OPERAND_REG9 0x9
#define CS_ALU_OPERAND_REG10 0xa
#define CS_ALU_OPERAND_REG11 0xb
#define CS_ALU_OPERAND_REG12 0xc
#define CS_ALU_OPERAND_REG13 0xd
#define CS_ALU_OPERAND_REG14 0xe
#define CS_ALU_OPERAND_REG15 0xf
#define CS_ALU_OPERAND_SRCA 0x20
#define CS_ALU_OPERAND_SRCB 0x21
#define CS_ALU_OPERAND_ACCU 0x31
#define CS_ALU_OPERAND_ZF 0x32
#define CS_ALU_OPERAND_CF 0x33
#define CS_ALU_OPERAND_NA 0 /* N/A operand */
/* Command Streamer ALU Instructions */
#define CS_ALU_INSTR(opcode, op1, op2) (REG_FIELD_PREP(GENMASK(31, 20), (opcode)) | \
REG_FIELD_PREP(GENMASK(19, 10), (op1)) | \
REG_FIELD_PREP(GENMASK(9, 0), (op2)))
#define __CS_ALU_INSTR(opcode, op1, op2) CS_ALU_INSTR(CS_ALU_OPCODE_##opcode, \
CS_ALU_OPERAND_##op1, \
CS_ALU_OPERAND_##op2)
#define CS_ALU_INSTR_NOOP __CS_ALU_INSTR(NOOP, NA, NA)
#define CS_ALU_INSTR_LOAD(op1, op2) __CS_ALU_INSTR(LOAD, op1, op2)
#define CS_ALU_INSTR_LOADINV(op1, op2) __CS_ALU_INSTR(LOADINV, op1, op2)
#define CS_ALU_INSTR_LOAD0(op1) __CS_ALU_INSTR(LOAD0, op1, NA)
#define CS_ALU_INSTR_LOAD1(op1) __CS_ALU_INSTR(LOAD1, op1, NA)
#define CS_ALU_INSTR_ADD __CS_ALU_INSTR(ADD, NA, NA)
#define CS_ALU_INSTR_SUB __CS_ALU_INSTR(SUB, NA, NA)
#define CS_ALU_INSTR_AND __CS_ALU_INSTR(AND, NA, NA)
#define CS_ALU_INSTR_OR __CS_ALU_INSTR(OR, NA, NA)
#define CS_ALU_INSTR_XOR __CS_ALU_INSTR(XOR, NA, NA)
#define CS_ALU_INSTR_STORE(op1, op2) __CS_ALU_INSTR(STORE, op1, op2)
#define CS_ALU_INSTR_STOREINV(op1, op2) __CS_ALU_INSTR(STOREINV, op1, op2)
#endif
@@ -0,0 +1,18 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef _XE_GFX_STATE_COMMANDS_H_
#define _XE_GFX_STATE_COMMANDS_H_
#include "instructions/xe_instr_defs.h"
#define GFX_STATE_OPCODE REG_GENMASK(28, 26)
#define GFX_STATE_CMD(opcode) \
(XE_INSTR_GFX_STATE | REG_FIELD_PREP(GFX_STATE_OPCODE, opcode))
#define STATE_WRITE_INLINE GFX_STATE_CMD(0x0)
#endif
@@ -0,0 +1,174 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_GFXPIPE_COMMANDS_H_
#define _XE_GFXPIPE_COMMANDS_H_
#include "instructions/xe_instr_defs.h"
#define GFXPIPE_PIPELINE REG_GENMASK(28, 27)
#define PIPELINE_COMMON REG_FIELD_PREP(GFXPIPE_PIPELINE, 0x0)
#define PIPELINE_SINGLE_DW REG_FIELD_PREP(GFXPIPE_PIPELINE, 0x1)
#define PIPELINE_COMPUTE REG_FIELD_PREP(GFXPIPE_PIPELINE, 0x2)
#define PIPELINE_3D REG_FIELD_PREP(GFXPIPE_PIPELINE, 0x3)
#define GFXPIPE_OPCODE REG_GENMASK(26, 24)
#define GFXPIPE_SUBOPCODE REG_GENMASK(23, 16)
#define GFXPIPE_MATCH_MASK (XE_INSTR_CMD_TYPE | \
GFXPIPE_PIPELINE | \
GFXPIPE_OPCODE | \
GFXPIPE_SUBOPCODE)
#define GFXPIPE_COMMON_CMD(opcode, subopcode) \
(XE_INSTR_GFXPIPE | PIPELINE_COMMON | \
REG_FIELD_PREP(GFXPIPE_OPCODE, opcode) | \
REG_FIELD_PREP(GFXPIPE_SUBOPCODE, subopcode))
#define GFXPIPE_SINGLE_DW_CMD(opcode, subopcode) \
(XE_INSTR_GFXPIPE | PIPELINE_SINGLE_DW | \
REG_FIELD_PREP(GFXPIPE_OPCODE, opcode) | \
REG_FIELD_PREP(GFXPIPE_SUBOPCODE, subopcode))
#define GFXPIPE_3D_CMD(opcode, subopcode) \
(XE_INSTR_GFXPIPE | PIPELINE_3D | \
REG_FIELD_PREP(GFXPIPE_OPCODE, opcode) | \
REG_FIELD_PREP(GFXPIPE_SUBOPCODE, subopcode))
#define GFXPIPE_COMPUTE_CMD(opcode, subopcode) \
(XE_INSTR_GFXPIPE | PIPELINE_COMPUTE | \
REG_FIELD_PREP(GFXPIPE_OPCODE, opcode) | \
REG_FIELD_PREP(GFXPIPE_SUBOPCODE, subopcode))
#define STATE_BASE_ADDRESS GFXPIPE_COMMON_CMD(0x1, 0x1)
#define STATE_SIP GFXPIPE_COMMON_CMD(0x1, 0x2)
#define GPGPU_CSR_BASE_ADDRESS GFXPIPE_COMMON_CMD(0x1, 0x4)
#define STATE_COMPUTE_MODE GFXPIPE_COMMON_CMD(0x1, 0x5)
#define CMD_3DSTATE_BTD GFXPIPE_COMMON_CMD(0x1, 0x6)
#define STATE_SYSTEM_MEM_FENCE_ADDRESS GFXPIPE_COMMON_CMD(0x1, 0x9)
#define STATE_CONTEXT_DATA_BASE_ADDRESS GFXPIPE_COMMON_CMD(0x1, 0xB)
#define CMD_3DSTATE_VF_STATISTICS GFXPIPE_SINGLE_DW_CMD(0x0, 0xB)
#define PIPELINE_SELECT GFXPIPE_SINGLE_DW_CMD(0x1, 0x4)
#define CMD_3DSTATE_DRAWING_RECTANGLE_FAST GFXPIPE_3D_CMD(0x0, 0x0)
#define CMD_3DSTATE_CUSTOM_SAMPLE_PATTERN GFXPIPE_3D_CMD(0x0, 0x2)
#define CMD_3DSTATE_CLEAR_PARAMS GFXPIPE_3D_CMD(0x0, 0x4)
#define CMD_3DSTATE_DEPTH_BUFFER GFXPIPE_3D_CMD(0x0, 0x5)
#define CMD_3DSTATE_STENCIL_BUFFER GFXPIPE_3D_CMD(0x0, 0x6)
#define CMD_3DSTATE_HIER_DEPTH_BUFFER GFXPIPE_3D_CMD(0x0, 0x7)
#define CMD_3DSTATE_VERTEX_BUFFERS GFXPIPE_3D_CMD(0x0, 0x8)
#define CMD_3DSTATE_VERTEX_ELEMENTS GFXPIPE_3D_CMD(0x0, 0x9)
#define CMD_3DSTATE_INDEX_BUFFER GFXPIPE_3D_CMD(0x0, 0xA)
#define CMD_3DSTATE_VF GFXPIPE_3D_CMD(0x0, 0xC)
#define CMD_3DSTATE_MULTISAMPLE GFXPIPE_3D_CMD(0x0, 0xD)
#define CMD_3DSTATE_CC_STATE_POINTERS GFXPIPE_3D_CMD(0x0, 0xE)
#define CMD_3DSTATE_SCISSOR_STATE_POINTERS GFXPIPE_3D_CMD(0x0, 0xF)
#define CMD_3DSTATE_VS GFXPIPE_3D_CMD(0x0, 0x10)
#define CMD_3DSTATE_GS GFXPIPE_3D_CMD(0x0, 0x11)
#define CMD_3DSTATE_CLIP GFXPIPE_3D_CMD(0x0, 0x12)
#define CMD_3DSTATE_SF GFXPIPE_3D_CMD(0x0, 0x13)
#define CMD_3DSTATE_WM GFXPIPE_3D_CMD(0x0, 0x14)
#define CMD_3DSTATE_CONSTANT_VS GFXPIPE_3D_CMD(0x0, 0x15)
#define CMD_3DSTATE_CONSTANT_GS GFXPIPE_3D_CMD(0x0, 0x16)
#define CMD_3DSTATE_CONSTANT_PS GFXPIPE_3D_CMD(0x0, 0x17)
#define CMD_3DSTATE_SAMPLE_MASK GFXPIPE_3D_CMD(0x0, 0x18)
#define CMD_3DSTATE_CONSTANT_HS GFXPIPE_3D_CMD(0x0, 0x19)
#define CMD_3DSTATE_CONSTANT_DS GFXPIPE_3D_CMD(0x0, 0x1A)
#define CMD_3DSTATE_HS GFXPIPE_3D_CMD(0x0, 0x1B)
#define CMD_3DSTATE_TE GFXPIPE_3D_CMD(0x0, 0x1C)
#define CMD_3DSTATE_DS GFXPIPE_3D_CMD(0x0, 0x1D)
#define CMD_3DSTATE_STREAMOUT GFXPIPE_3D_CMD(0x0, 0x1E)
#define CMD_3DSTATE_SBE GFXPIPE_3D_CMD(0x0, 0x1F)
#define CMD_3DSTATE_PS GFXPIPE_3D_CMD(0x0, 0x20)
#define CMD_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP GFXPIPE_3D_CMD(0x0, 0x21)
#define CMD_3DSTATE_CPS_POINTERS GFXPIPE_3D_CMD(0x0, 0x22)
#define CMD_3DSTATE_VIEWPORT_STATE_POINTERS_CC GFXPIPE_3D_CMD(0x0, 0x23)
#define CMD_3DSTATE_BLEND_STATE_POINTERS GFXPIPE_3D_CMD(0x0, 0x24)
#define CMD_3DSTATE_BINDING_TABLE_POINTERS_VS GFXPIPE_3D_CMD(0x0, 0x26)
#define CMD_3DSTATE_BINDING_TABLE_POINTERS_HS GFXPIPE_3D_CMD(0x0, 0x27)
#define CMD_3DSTATE_BINDING_TABLE_POINTERS_DS GFXPIPE_3D_CMD(0x0, 0x28)
#define CMD_3DSTATE_BINDING_TABLE_POINTERS_GS GFXPIPE_3D_CMD(0x0, 0x29)
#define CMD_3DSTATE_BINDING_TABLE_POINTERS_PS GFXPIPE_3D_CMD(0x0, 0x2A)
#define CMD_3DSTATE_SAMPLER_STATE_POINTERS_VS GFXPIPE_3D_CMD(0x0, 0x2B)
#define CMD_3DSTATE_SAMPLER_STATE_POINTERS_HS GFXPIPE_3D_CMD(0x0, 0x2C)
#define CMD_3DSTATE_SAMPLER_STATE_POINTERS_DS GFXPIPE_3D_CMD(0x0, 0x2D)
#define CMD_3DSTATE_SAMPLER_STATE_POINTERS_GS GFXPIPE_3D_CMD(0x0, 0x2E)
#define CMD_3DSTATE_SAMPLER_STATE_POINTERS_PS GFXPIPE_3D_CMD(0x0, 0x2F)
#define CMD_3DSTATE_VF_INSTANCING GFXPIPE_3D_CMD(0x0, 0x49)
#define CMD_3DSTATE_VF_SGVS GFXPIPE_3D_CMD(0x0, 0x4A)
#define CMD_3DSTATE_VF_TOPOLOGY GFXPIPE_3D_CMD(0x0, 0x4B)
#define CMD_3DSTATE_WM_CHROMAKEY GFXPIPE_3D_CMD(0x0, 0x4C)
#define CMD_3DSTATE_PS_BLEND GFXPIPE_3D_CMD(0x0, 0x4D)
#define CMD_3DSTATE_WM_DEPTH_STENCIL GFXPIPE_3D_CMD(0x0, 0x4E)
#define CMD_3DSTATE_PS_EXTRA GFXPIPE_3D_CMD(0x0, 0x4F)
#define CMD_3DSTATE_RASTER GFXPIPE_3D_CMD(0x0, 0x50)
#define CMD_3DSTATE_SBE_SWIZ GFXPIPE_3D_CMD(0x0, 0x51)
#define CMD_3DSTATE_WM_HZ_OP GFXPIPE_3D_CMD(0x0, 0x52)
#define CMD_3DSTATE_VF_COMPONENT_PACKING GFXPIPE_3D_CMD(0x0, 0x55)
#define CMD_3DSTATE_VF_SGVS_2 GFXPIPE_3D_CMD(0x0, 0x56)
#define CMD_3DSTATE_VFG GFXPIPE_3D_CMD(0x0, 0x57)
#define CMD_3DSTATE_URB_ALLOC_VS GFXPIPE_3D_CMD(0x0, 0x58)
#define CMD_3DSTATE_URB_ALLOC_HS GFXPIPE_3D_CMD(0x0, 0x59)
#define CMD_3DSTATE_URB_ALLOC_DS GFXPIPE_3D_CMD(0x0, 0x5A)
#define CMD_3DSTATE_URB_ALLOC_GS GFXPIPE_3D_CMD(0x0, 0x5B)
#define CMD_3DSTATE_SO_BUFFER_INDEX_0 GFXPIPE_3D_CMD(0x0, 0x60)
#define CMD_3DSTATE_SO_BUFFER_INDEX_1 GFXPIPE_3D_CMD(0x0, 0x61)
#define CMD_3DSTATE_SO_BUFFER_INDEX_2 GFXPIPE_3D_CMD(0x0, 0x62)
#define CMD_3DSTATE_SO_BUFFER_INDEX_3 GFXPIPE_3D_CMD(0x0, 0x63)
#define CMD_3DSTATE_PRIMITIVE_REPLICATION GFXPIPE_3D_CMD(0x0, 0x6C)
#define CMD_3DSTATE_TBIMR_TILE_PASS_INFO GFXPIPE_3D_CMD(0x0, 0x6E)
#define CMD_3DSTATE_AMFS GFXPIPE_3D_CMD(0x0, 0x6F)
#define CMD_3DSTATE_DEPTH_BOUNDS GFXPIPE_3D_CMD(0x0, 0x71)
#define CMD_3DSTATE_AMFS_TEXTURE_POINTERS GFXPIPE_3D_CMD(0x0, 0x72)
#define CMD_3DSTATE_CONSTANT_TS_POINTER GFXPIPE_3D_CMD(0x0, 0x73)
#define CMD_3DSTATE_MESH_CONTROL GFXPIPE_3D_CMD(0x0, 0x77)
#define CMD_3DSTATE_MESH_DISTRIB GFXPIPE_3D_CMD(0x0, 0x78)
#define CMD_3DSTATE_TASK_REDISTRIB GFXPIPE_3D_CMD(0x0, 0x79)
#define CMD_3DSTATE_MESH_SHADER GFXPIPE_3D_CMD(0x0, 0x7A)
#define CMD_3DSTATE_MESH_SHADER_DATA GFXPIPE_3D_CMD(0x0, 0x7B)
#define CMD_3DSTATE_TASK_CONTROL GFXPIPE_3D_CMD(0x0, 0x7C)
#define CMD_3DSTATE_TASK_SHADER GFXPIPE_3D_CMD(0x0, 0x7D)
#define CMD_3DSTATE_TASK_SHADER_DATA GFXPIPE_3D_CMD(0x0, 0x7E)
#define CMD_3DSTATE_URB_ALLOC_MESH GFXPIPE_3D_CMD(0x0, 0x7F)
#define CMD_3DSTATE_URB_ALLOC_TASK GFXPIPE_3D_CMD(0x0, 0x80)
#define CMD_3DSTATE_CLIP_MESH GFXPIPE_3D_CMD(0x0, 0x81)
#define CMD_3DSTATE_SBE_MESH GFXPIPE_3D_CMD(0x0, 0x82)
#define CMD_3DSTATE_CPSIZE_CONTROL_BUFFER GFXPIPE_3D_CMD(0x0, 0x83)
#define CMD_3DSTATE_COARSE_PIXEL GFXPIPE_3D_CMD(0x0, 0x89)
#define CMD_3DSTATE_MESH_SHADER_DATA_EXT GFXPIPE_3D_CMD(0x0, 0x8A)
#define CMD_3DSTATE_TASK_SHADER_DATA_EXT GFXPIPE_3D_CMD(0x0, 0x8B)
#define CMD_3DSTATE_VIEWPORT_STATE_POINTERS_CC_2 GFXPIPE_3D_CMD(0x0, 0x8D)
#define CMD_3DSTATE_CC_STATE_POINTERS_2 GFXPIPE_3D_CMD(0x0, 0x8E)
#define CMD_3DSTATE_SCISSOR_STATE_POINTERS_2 GFXPIPE_3D_CMD(0x0, 0x8F)
#define CMD_3DSTATE_BLEND_STATE_POINTERS_2 GFXPIPE_3D_CMD(0x0, 0xA0)
#define CMD_3DSTATE_VIEWPORT_STATE_POINTERS_SF_CLIP_2 GFXPIPE_3D_CMD(0x0, 0xA1)
#define CMD_3DSTATE_DRAWING_RECTANGLE GFXPIPE_3D_CMD(0x1, 0x0)
#define CMD_3DSTATE_URB_MEMORY GFXPIPE_3D_CMD(0x1, 0x1)
#define CMD_3DSTATE_CHROMA_KEY GFXPIPE_3D_CMD(0x1, 0x4)
#define CMD_3DSTATE_POLY_STIPPLE_OFFSET GFXPIPE_3D_CMD(0x1, 0x6)
#define CMD_3DSTATE_POLY_STIPPLE_PATTERN GFXPIPE_3D_CMD(0x1, 0x7)
#define CMD_3DSTATE_LINE_STIPPLE GFXPIPE_3D_CMD(0x1, 0x8)
#define CMD_3DSTATE_AA_LINE_PARAMETERS GFXPIPE_3D_CMD(0x1, 0xA)
#define CMD_3DSTATE_MONOFILTER_SIZE GFXPIPE_3D_CMD(0x1, 0x11)
#define CMD_3DSTATE_PUSH_CONSTANT_ALLOC_VS GFXPIPE_3D_CMD(0x1, 0x12)
#define CMD_3DSTATE_PUSH_CONSTANT_ALLOC_HS GFXPIPE_3D_CMD(0x1, 0x13)
#define CMD_3DSTATE_PUSH_CONSTANT_ALLOC_DS GFXPIPE_3D_CMD(0x1, 0x14)
#define CMD_3DSTATE_PUSH_CONSTANT_ALLOC_GS GFXPIPE_3D_CMD(0x1, 0x15)
#define CMD_3DSTATE_PUSH_CONSTANT_ALLOC_PS GFXPIPE_3D_CMD(0x1, 0x16)
#define CMD_3DSTATE_SO_DECL_LIST GFXPIPE_3D_CMD(0x1, 0x17)
#define CMD_3DSTATE_SO_DECL_LIST_DW_LEN REG_GENMASK(8, 0)
#define CMD_3DSTATE_SO_BUFFER GFXPIPE_3D_CMD(0x1, 0x18)
#define CMD_3DSTATE_BINDING_TABLE_POOL_ALLOC GFXPIPE_3D_CMD(0x1, 0x19)
#define CMD_3DSTATE_SAMPLE_PATTERN GFXPIPE_3D_CMD(0x1, 0x1C)
#define CMD_3DSTATE_3D_MODE GFXPIPE_3D_CMD(0x1, 0x1E)
#define CMD_3DSTATE_SUBSLICE_HASH_TABLE GFXPIPE_3D_CMD(0x1, 0x1F)
#define CMD_3DSTATE_SLICE_TABLE_STATE_POINTERS GFXPIPE_3D_CMD(0x1, 0x20)
#define CMD_3DSTATE_PTBR_TILE_PASS_INFO GFXPIPE_3D_CMD(0x1, 0x22)
#define CMD_3DSTATE_SLICE_TABLE_STATE_POINTER_2 GFXPIPE_3D_CMD(0x1, 0xA0)
#endif
@@ -0,0 +1,76 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_GPU_COMMANDS_H_
#define _XE_GPU_COMMANDS_H_
#include "regs/xe_reg_defs.h"
#define XY_CTRL_SURF_COPY_BLT ((2 << 29) | (0x48 << 22) | 3)
#define SRC_ACCESS_TYPE_SHIFT 21
#define DST_ACCESS_TYPE_SHIFT 20
#define CCS_SIZE_MASK GENMASK(17, 8)
#define XE2_CCS_SIZE_MASK GENMASK(18, 9)
#define XY_CTRL_SURF_MOCS_MASK GENMASK(31, 26)
#define XE2_XY_CTRL_SURF_MOCS_INDEX_MASK GENMASK(31, 28)
#define NUM_CCS_BYTES_PER_BLOCK 256
#define NUM_BYTES_PER_CCS_BYTE(_xe) (GRAPHICS_VER(_xe) >= 20 ? 512 : 256)
#define XY_FAST_COLOR_BLT_CMD (2 << 29 | 0x44 << 22)
#define XY_FAST_COLOR_BLT_DEPTH_32 (2 << 19)
#define XY_FAST_COLOR_BLT_MOCS_MASK GENMASK(27, 22)
#define XE2_XY_FAST_COLOR_BLT_MOCS_INDEX_MASK GENMASK(27, 24)
#define XY_FAST_COLOR_BLT_MEM_TYPE_SHIFT 31
#define XY_FAST_COPY_BLT_CMD (2 << 29 | 0x42 << 22)
#define XY_FAST_COPY_BLT_DEPTH_32 (3<<24)
#define XY_FAST_COPY_BLT_D1_SRC_TILE4 REG_BIT(31)
#define XY_FAST_COPY_BLT_D1_DST_TILE4 REG_BIT(30)
#define XE2_XY_FAST_COPY_BLT_MOCS_INDEX_MASK GENMASK(23, 20)
#define MEM_COPY_CMD (2 << 29 | 0x5a << 22)
#define MEM_COPY_PAGE_COPY_MODE REG_BIT(19)
#define MEM_COPY_MATRIX_COPY REG_BIT(17)
#define MEM_COPY_SRC_MOCS_INDEX_MASK GENMASK(31, 28)
#define MEM_COPY_DST_MOCS_INDEX_MASK GENMASK(6, 3)
#define PVC_MEM_SET_CMD (2 << 29 | 0x5b << 22)
#define PVC_MEM_SET_MATRIX REG_BIT(17)
#define PVC_MEM_SET_DATA_FIELD GENMASK(31, 24)
/* Bspec lists field as [6:0], but index alone is from [6:1] */
#define PVC_MEM_SET_MOCS_INDEX_MASK GENMASK(6, 1)
#define XE2_MEM_SET_MOCS_INDEX_MASK GENMASK(6, 3)
#define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|((len)-2))
#define PIPE_CONTROL0_QUEUE_DRAIN_MODE BIT(12)
#define PIPE_CONTROL0_L3_READ_ONLY_CACHE_INVALIDATE BIT(10) /* gen12 */
#define PIPE_CONTROL0_HDC_PIPELINE_FLUSH BIT(9) /* gen12 */
#define PIPE_CONTROL_COMMAND_CACHE_INVALIDATE (1<<29)
#define PIPE_CONTROL_TILE_CACHE_FLUSH (1<<28)
#define PIPE_CONTROL_AMFS_FLUSH (1<<25)
#define PIPE_CONTROL_GLOBAL_GTT_IVB (1<<24)
#define PIPE_CONTROL_LRI_POST_SYNC BIT(23)
#define PIPE_CONTROL_STORE_DATA_INDEX (1<<21)
#define PIPE_CONTROL_CS_STALL (1<<20)
#define PIPE_CONTROL_GLOBAL_SNAPSHOT_RESET (1<<19)
#define PIPE_CONTROL_TLB_INVALIDATE BIT(18)
#define PIPE_CONTROL_PSD_SYNC (1<<17)
#define PIPE_CONTROL_QW_WRITE (1<<14)
#define PIPE_CONTROL_DEPTH_STALL (1<<13)
#define PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH (1<<12)
#define PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE (1<<11)
#define PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE (1<<10)
#define PIPE_CONTROL_INDIRECT_STATE_DISABLE (1<<9)
#define PIPE_CONTROL_FLUSH_ENABLE (1<<7)
#define PIPE_CONTROL_DC_FLUSH_ENABLE (1<<5)
#define PIPE_CONTROL_VF_CACHE_INVALIDATE (1<<4)
#define PIPE_CONTROL_CONST_CACHE_INVALIDATE (1<<3)
#define PIPE_CONTROL_STATE_CACHE_INVALIDATE (1<<2)
#define PIPE_CONTROL_STALL_AT_SCOREBOARD (1<<1)
#define PIPE_CONTROL_DEPTH_CACHE_FLUSH (1<<0)
#endif
@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_GSC_COMMANDS_H_
#define _XE_GSC_COMMANDS_H_
#include "instructions/xe_instr_defs.h"
/*
* All GSCCS-specific commands have fixed length, so we can include it in the
* defines. Note that the generic GSC command header structure includes an
* optional data field in bits 9-21, but there are no commands that actually use
* it; some of the commands are instead defined as having an extended length
* field spanning bits 0-15, even if the extra bits are not required because the
* longest GSCCS command is only 8 dwords. To handle this, the defines below use
* a single field for both data and len. If we ever get a commands that does
* actually have data and this approach doesn't work for it we can re-work it
* at that point.
*/
#define GSC_OPCODE REG_GENMASK(28, 22)
#define GSC_CMD_DATA_AND_LEN REG_GENMASK(21, 0)
#define __GSC_INSTR(op, dl) \
(XE_INSTR_GSC | \
REG_FIELD_PREP(GSC_OPCODE, op) | \
REG_FIELD_PREP(GSC_CMD_DATA_AND_LEN, dl))
#define GSC_HECI_CMD_PKT __GSC_INSTR(0, 6)
#define GSC_FW_LOAD __GSC_INSTR(1, 2)
#define GSC_FW_LOAD_LIMIT_VALID REG_BIT(31)
#endif
@@ -0,0 +1,35 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_INSTR_DEFS_H_
#define _XE_INSTR_DEFS_H_
#include "regs/xe_reg_defs.h"
/*
* The first dword of any GPU instruction is the "instruction header." Bits
* 31:29 identify the general type of the command and determine how exact
* opcodes and sub-opcodes will be encoded in the remaining bits.
*/
#define XE_INSTR_CMD_TYPE GENMASK(31, 29)
#define XE_INSTR_MI REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x0)
#define XE_INSTR_GSC REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x2)
#define XE_INSTR_VIDEOPIPE REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x3)
#define XE_INSTR_GFXPIPE REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x3)
#define XE_INSTR_GFX_STATE REG_FIELD_PREP(XE_INSTR_CMD_TYPE, 0x4)
/*
* Most (but not all) instructions have a "length" field in the instruction
* header. The value expected is the total number of dwords for the
* instruction, minus two.
*
* Some instructions have length fields longer or shorter than 8 bits, but
* those are rare. This definition can be used for the common case where
* the length field is from 7:0.
*/
#define XE_INSTR_LEN_MASK GENMASK(7, 0)
#define XE_INSTR_NUM_DW(x) REG_FIELD_PREP(XE_INSTR_LEN_MASK, (x) - 2)
#endif
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef _XE_MFX_COMMANDS_H_
#define _XE_MFX_COMMANDS_H_
#include "instructions/xe_instr_defs.h"
#define MFX_CMD_SUBTYPE REG_GENMASK(28, 27) /* A.K.A cmd pipe */
#define MFX_CMD_OPCODE REG_GENMASK(26, 24)
#define MFX_CMD_SUB_OPCODE REG_GENMASK(23, 16)
#define MFX_FLAGS_AND_LEN REG_GENMASK(15, 0)
#define XE_MFX_INSTR(subtype, op, sub_op) \
(XE_INSTR_VIDEOPIPE | \
REG_FIELD_PREP(MFX_CMD_SUBTYPE, subtype) | \
REG_FIELD_PREP(MFX_CMD_OPCODE, op) | \
REG_FIELD_PREP(MFX_CMD_SUB_OPCODE, sub_op))
#define MFX_WAIT XE_MFX_INSTR(1, 0, 0)
#define MFX_WAIT_DW0_PXP_SYNC_CONTROL_FLAG REG_BIT(9)
#define MFX_WAIT_DW0_MFX_SYNC_CONTROL_FLAG REG_BIT(8)
#define CRYPTO_KEY_EXCHANGE XE_MFX_INSTR(2, 6, 9)
#endif
@@ -0,0 +1,103 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_MI_COMMANDS_H_
#define _XE_MI_COMMANDS_H_
#include "instructions/xe_instr_defs.h"
/*
* MI (Memory Interface) commands are supported by all GT engines. They
* provide general memory operations and command streamer control. MI commands
* have a command type of 0x0 (MI_COMMAND) in bits 31:29 of the instruction
* header dword and a specific MI opcode in bits 28:23.
*/
#define MI_OPCODE REG_GENMASK(28, 23)
#define MI_SUBOPCODE REG_GENMASK(22, 17) /* used with MI_EXPANSION */
#define __MI_INSTR(opcode) \
(XE_INSTR_MI | REG_FIELD_PREP(MI_OPCODE, opcode))
#define MI_NOOP __MI_INSTR(0x0)
#define MI_USER_INTERRUPT __MI_INSTR(0x2)
#define MI_ARB_CHECK __MI_INSTR(0x5)
#define MI_ARB_ON_OFF __MI_INSTR(0x8)
#define MI_ARB_ENABLE REG_BIT(0)
#define MI_ARB_DISABLE 0x0
#define MI_BATCH_BUFFER_END __MI_INSTR(0xA)
#define MI_TOPOLOGY_FILTER __MI_INSTR(0xD)
#define MI_FORCE_WAKEUP __MI_INSTR(0x1D)
#define MI_MATH(n) (__MI_INSTR(0x1A) | XE_INSTR_NUM_DW((n) + 1))
#define MI_SEMAPHORE_WAIT (__MI_INSTR(0x1c) | XE_INSTR_NUM_DW(5))
#define MI_SEMW_GGTT REG_BIT(22)
#define MI_SEMW_POLL REG_BIT(15)
#define MI_SEMW_COMPARE_OP_MASK REG_GENMASK(14, 12)
#define COMPARE_OP_SAD_GT_SDD 0
#define COMPARE_OP_SAD_GTE_SDD 1
#define COMPARE_OP_SAD_LT_SDD 2
#define COMPARE_OP_SAD_LTE_SDD 3
#define COMPARE_OP_SAD_EQ_SDD 4
#define COMPARE_OP_SAD_NEQ_SDD 5
#define MI_SEMW_COMPARE(OP) REG_FIELD_PREP(MI_SEMW_COMPARE_OP_MASK, COMPARE_OP_##OP)
#define MI_SEMW_TOKEN(token) REG_FIELD_PREP(REG_GENMASK(9, 2), (token))
#define MI_STORE_DATA_IMM __MI_INSTR(0x20)
#define MI_SDI_GGTT REG_BIT(22)
#define MI_SDI_LEN_DW GENMASK(9, 0)
#define MI_SDI_NUM_DW(x) REG_FIELD_PREP(MI_SDI_LEN_DW, (x) + 3 - 2)
#define MI_SDI_NUM_QW(x) (REG_FIELD_PREP(MI_SDI_LEN_DW, 2 * (x) + 3 - 2) | \
REG_BIT(21))
#define MI_LOAD_REGISTER_IMM __MI_INSTR(0x22)
#define MI_LRI_LRM_CS_MMIO REG_BIT(19)
#define MI_LRI_MMIO_REMAP_EN REG_BIT(17)
#define MI_LRI_NUM_REGS(x) XE_INSTR_NUM_DW(2 * (x) + 1)
#define MI_LRI_FORCE_POSTED REG_BIT(12)
#define MI_LRI_LEN(x) (((x) & 0xff) + 1)
#define MI_STORE_REGISTER_MEM (__MI_INSTR(0x24) | XE_INSTR_NUM_DW(4))
#define MI_SRM_USE_GGTT REG_BIT(22)
#define MI_SRM_ADD_CS_OFFSET REG_BIT(19)
#define MI_FLUSH_DW __MI_INSTR(0x26)
#define MI_FLUSH_DW_PROTECTED_MEM_EN REG_BIT(22)
#define MI_FLUSH_DW_STORE_INDEX REG_BIT(21)
#define MI_INVALIDATE_TLB REG_BIT(18)
#define MI_FLUSH_DW_CCS REG_BIT(16)
#define MI_FLUSH_DW_OP_STOREDW REG_BIT(14)
#define MI_FLUSH_DW_LEN_DW REG_GENMASK(5, 0)
#define MI_FLUSH_IMM_DW REG_FIELD_PREP(MI_FLUSH_DW_LEN_DW, 4 - 2)
#define MI_FLUSH_IMM_QW REG_FIELD_PREP(MI_FLUSH_DW_LEN_DW, 5 - 2)
#define MI_FLUSH_DW_USE_GTT REG_BIT(2)
#define MI_LOAD_REGISTER_MEM (__MI_INSTR(0x29) | XE_INSTR_NUM_DW(4))
#define MI_LRM_USE_GGTT REG_BIT(22)
#define MI_LRM_ASYNC REG_BIT(21)
#define MI_LOAD_REGISTER_REG (__MI_INSTR(0x2a) | XE_INSTR_NUM_DW(3))
#define MI_LRR_DST_CS_MMIO REG_BIT(19)
#define MI_LRR_SRC_CS_MMIO REG_BIT(18)
#define MI_COPY_MEM_MEM (__MI_INSTR(0x2e) | XE_INSTR_NUM_DW(5))
#define MI_COPY_MEM_MEM_SRC_GGTT REG_BIT(22)
#define MI_COPY_MEM_MEM_DST_GGTT REG_BIT(21)
#define MI_BATCH_BUFFER_START __MI_INSTR(0x31)
#define MI_SET_APPID __MI_INSTR(0x0e)
#define MI_SET_APPID_SESSION_ID_MASK REG_GENMASK(6, 0)
#define MI_SET_APPID_SESSION_ID(x) REG_FIELD_PREP(MI_SET_APPID_SESSION_ID_MASK, x)
#define MI_SEMAPHORE_WAIT_TOKEN (__MI_INSTR(0x1c) | XE_INSTR_NUM_DW(5)) /* XeLP+ */
#define MI_SEMAPHORE_REGISTER_POLL REG_BIT(16)
#define MI_SEMAPHORE_POLL REG_BIT(15)
#define MI_SEMAPHORE_CMP_OP_MASK REG_GENMASK(14, 12)
#define MI_SEMAPHORE_SAD_EQ_SDD REG_FIELD_PREP(MI_SEMAPHORE_CMP_OP_MASK, 4)
#endif
@@ -0,0 +1,12 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef _XE_BARS_H_
#define _XE_BARS_H_
#define GTTMMADR_BAR 0 /* MMIO + GTT */
#define LMEM_BAR 2 /* VRAM */
#define VF_LMEM_BAR 9 /* VF VRAM */
#endif
@@ -0,0 +1,237 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_ENGINE_REGS_H_
#define _XE_ENGINE_REGS_H_
#include <asm/page.h>
#include "regs/xe_reg_defs.h"
/*
* These *_BASE values represent the MMIO offset where each hardware engine's
* registers start. The other definitions in this header are parameterized
* macros that will take one of these values as a parameter.
*/
#define RENDER_RING_BASE 0x02000
#define BSD_RING_BASE 0x1c0000
#define BSD2_RING_BASE 0x1c4000
#define BSD3_RING_BASE 0x1d0000
#define BSD4_RING_BASE 0x1d4000
#define XEHP_BSD5_RING_BASE 0x1e0000
#define XEHP_BSD6_RING_BASE 0x1e4000
#define XEHP_BSD7_RING_BASE 0x1f0000
#define XEHP_BSD8_RING_BASE 0x1f4000
#define VEBOX_RING_BASE 0x1c8000
#define VEBOX2_RING_BASE 0x1d8000
#define XEHP_VEBOX3_RING_BASE 0x1e8000
#define XEHP_VEBOX4_RING_BASE 0x1f8000
#define COMPUTE0_RING_BASE 0x1a000
#define COMPUTE1_RING_BASE 0x1c000
#define COMPUTE2_RING_BASE 0x1e000
#define COMPUTE3_RING_BASE 0x26000
#define BLT_RING_BASE 0x22000
#define XEHPC_BCS1_RING_BASE 0x3e0000
#define XEHPC_BCS2_RING_BASE 0x3e2000
#define XEHPC_BCS3_RING_BASE 0x3e4000
#define XEHPC_BCS4_RING_BASE 0x3e6000
#define XEHPC_BCS5_RING_BASE 0x3e8000
#define XEHPC_BCS6_RING_BASE 0x3ea000
#define XEHPC_BCS7_RING_BASE 0x3ec000
#define XEHPC_BCS8_RING_BASE 0x3ee000
#define GSCCS_RING_BASE 0x11a000
#define ENGINE_ID(base) XE_REG((base) + 0x8c)
#define ENGINE_INSTANCE_ID REG_GENMASK(9, 4)
#define ENGINE_CLASS_ID REG_GENMASK(2, 0)
#define RING_TAIL(base) XE_REG((base) + 0x30)
#define TAIL_ADDR REG_GENMASK(20, 3)
#define RING_HEAD(base) XE_REG((base) + 0x34)
#define HEAD_ADDR REG_GENMASK(20, 2)
#define RING_START(base) XE_REG((base) + 0x38)
#define RING_CTL(base) XE_REG((base) + 0x3c)
#define RING_CTL_SIZE(size) ((size) - PAGE_SIZE) /* in bytes -> pages */
#define RING_START_UDW(base) XE_REG((base) + 0x48)
#define RING_PSMI_CTL(base) XE_REG((base) + 0x50, XE_REG_OPTION_MASKED)
#define RC_SEMA_IDLE_MSG_DISABLE REG_BIT(12)
#define WAIT_FOR_EVENT_POWER_DOWN_DISABLE REG_BIT(7)
#define IDLE_MSG_DISABLE REG_BIT(0)
#define RING_PWRCTX_MAXCNT(base) XE_REG((base) + 0x54)
#define IDLE_WAIT_TIME REG_GENMASK(19, 0)
#define RING_ACTHD_UDW(base) XE_REG((base) + 0x5c)
#define RING_DMA_FADD_UDW(base) XE_REG((base) + 0x60)
#define RING_IPEHR(base) XE_REG((base) + 0x68)
#define RING_INSTDONE(base) XE_REG((base) + 0x6c)
#define RING_ACTHD(base) XE_REG((base) + 0x74)
#define RING_DMA_FADD(base) XE_REG((base) + 0x78)
#define RING_HWS_PGA(base) XE_REG((base) + 0x80)
#define RING_HWSTAM(base) XE_REG((base) + 0x98)
#define RING_MI_MODE(base) XE_REG((base) + 0x9c)
#define RING_NOPID(base) XE_REG((base) + 0x94)
#define FF_THREAD_MODE(base) XE_REG((base) + 0xa0)
#define FF_TESSELATION_DOP_GATE_DISABLE BIT(19)
#define RING_INT_SRC_RPT_PTR(base) XE_REG((base) + 0xa4)
#define RING_IMR(base) XE_REG((base) + 0xa8)
#define RING_INT_STATUS_RPT_PTR(base) XE_REG((base) + 0xac)
#define CS_INT_VEC(base) XE_REG((base) + 0x1b8)
#define RING_EIR(base) XE_REG((base) + 0xb0)
#define RING_EMR(base) XE_REG((base) + 0xb4)
#define RING_ESR(base) XE_REG((base) + 0xb8)
#define INSTPM(base) XE_REG((base) + 0xc0, XE_REG_OPTION_MASKED)
#define ENABLE_SEMAPHORE_POLL_BIT REG_BIT(13)
#define RING_CMD_CCTL(base) XE_REG((base) + 0xc4, XE_REG_OPTION_MASKED)
#define CS_MMIO_GROUP_INSTANCE_SELECT(base) XE_REG((base) + 0xcc)
#define SELECTIVE_READ_ADDRESSING REG_BIT(30)
#define SELECTIVE_READ_GROUP REG_GENMASK(29, 23)
#define SELECTIVE_READ_INSTANCE REG_GENMASK(22, 16)
/*
* CMD_CCTL read/write fields take a MOCS value and _not_ a table index.
* The lsb of each can be considered a separate enabling bit for encryption.
* 6:0 == default MOCS value for reads => 6:1 == table index for reads.
* 13:7 == default MOCS value for writes => 13:8 == table index for writes.
* 15:14 == Reserved => 31:30 are set to 0.
*/
#define CMD_CCTL_WRITE_OVERRIDE_MASK REG_GENMASK(13, 8)
#define CMD_CCTL_READ_OVERRIDE_MASK REG_GENMASK(6, 1)
#define CSFE_CHICKEN1(base) XE_REG((base) + 0xd4, XE_REG_OPTION_MASKED)
#define GHWSP_CSB_REPORT_DIS REG_BIT(15)
#define PPHWSP_CSB_AND_TIMESTAMP_REPORT_DIS REG_BIT(14)
#define CS_PRIORITY_MEM_READ REG_BIT(7)
#define CS_DEBUG_MODE2(base) XE_REG((base) + 0xd8, XE_REG_OPTION_MASKED)
#define INSTRUCTION_STATE_CACHE_INVALIDATE REG_BIT(6)
#define FF_SLICE_CS_CHICKEN1(base) XE_REG((base) + 0xe0, XE_REG_OPTION_MASKED)
#define FFSC_PERCTX_PREEMPT_CTRL REG_BIT(14)
#define CS_DEBUG_MODE1(base) XE_REG((base) + 0xec, XE_REG_OPTION_MASKED)
#define FF_DOP_CLOCK_GATE_DISABLE REG_BIT(1)
#define REPLAY_MODE_GRANULARITY REG_BIT(0)
#define INDIRECT_RING_STATE(base) XE_REG((base) + 0x108)
#define RING_BBADDR(base) XE_REG((base) + 0x140)
#define RING_BBADDR_UDW(base) XE_REG((base) + 0x168)
#define PR_CTR_CTRL(base) XE_REG((base) + 0x178)
#define CTR_COUNT_SELECT_FF REG_BIT(31)
#define CTR_LOGIC_OP_MASK REG_GENMASK(30, 0)
#define CTR_START 0
#define CTR_STOP 1
#define CTR_LOGIC_OP(OP) REG_FIELD_PREP(CTR_LOGIC_OP_MASK, CTR_##OP)
#define PR_CTR_THRSH(base) XE_REG((base) + 0x17c)
#define BCS_SWCTRL(base) XE_REG((base) + 0x200, XE_REG_OPTION_MASKED)
#define BCS_SWCTRL_DISABLE_256B REG_BIT(2)
/* Handling MOCS value in BLIT_CCTL like it was done CMD_CCTL */
#define BLIT_CCTL(base) XE_REG((base) + 0x204)
#define BLIT_CCTL_DST_MOCS_MASK REG_GENMASK(14, 9)
#define BLIT_CCTL_SRC_MOCS_MASK REG_GENMASK(6, 1)
#define RING_EXECLIST_STATUS_LO(base) XE_REG((base) + 0x234)
#define RING_EXECLIST_STATUS_HI(base) XE_REG((base) + 0x234 + 4)
#define RING_IDLEDLY(base) XE_REG((base) + 0x23c)
#define INHIBIT_SWITCH_UNTIL_PREEMPTED REG_BIT(31)
#define IDLE_DELAY REG_GENMASK(20, 0)
#define RING_CURRENT_LRCA(base) XE_REG((base) + 0x240)
#define RING_CONTEXT_CONTROL(base) XE_REG((base) + 0x244, XE_REG_OPTION_MASKED)
#define CTX_CTRL_PXP_ENABLE REG_BIT(10)
#define CTX_CTRL_OAC_CONTEXT_ENABLE REG_BIT(8)
#define CTX_CTRL_RUN_ALONE REG_BIT(7)
#define CTX_CTRL_INDIRECT_RING_STATE_ENABLE REG_BIT(4)
#define CTX_CTRL_INHIBIT_SYN_CTX_SWITCH REG_BIT(3)
#define CTX_CTRL_ENGINE_CTX_RESTORE_INHIBIT REG_BIT(0)
#define GFX_MODE(base) XE_REG((base) + 0x29c, XE_REG_OPTION_MASKED)
#define GFX_MSIX_INTERRUPT_ENABLE REG_BIT(13)
#define GFX_DISABLE_LEGACY_MODE REG_BIT(3)
#define RING_CSMQDEBUG(base) XE_REG((base) + 0x2b0)
#define CURRENT_ACTIVE_QUEUE_ID_MASK REG_GENMASK(7, 0)
#define RING_QUEUE_TIMESTAMP(base) XE_REG((base) + 0x4c0)
#define RING_QUEUE_TIMESTAMP_UDW(base) XE_REG((base) + 0x4c0 + 4)
#define RING_TIMESTAMP(base) XE_REG((base) + 0x358)
#define RING_TIMESTAMP_UDW(base) XE_REG((base) + 0x358 + 4)
#define RING_VALID_MASK 0x00000001
#define RING_VALID 0x00000001
#define RING_CTX_TIMESTAMP(base) XE_REG((base) + 0x3a8)
#define RING_CTX_TIMESTAMP_UDW(base) XE_REG((base) + 0x3ac)
#define CSBE_DEBUG_STATUS(base) XE_REG((base) + 0x3fc)
#define RING_FORCE_TO_NONPRIV(base, i) XE_REG(((base) + 0x4d0) + (i) * 4)
#define RING_FORCE_TO_NONPRIV_DENY REG_BIT(30)
#define RING_FORCE_TO_NONPRIV_ACCESS_MASK REG_GENMASK(29, 28)
#define RING_FORCE_TO_NONPRIV_ACCESS_RW REG_FIELD_PREP(RING_FORCE_TO_NONPRIV_ACCESS_MASK, 0)
#define RING_FORCE_TO_NONPRIV_ACCESS_RD REG_FIELD_PREP(RING_FORCE_TO_NONPRIV_ACCESS_MASK, 1)
#define RING_FORCE_TO_NONPRIV_ACCESS_WR REG_FIELD_PREP(RING_FORCE_TO_NONPRIV_ACCESS_MASK, 2)
#define RING_FORCE_TO_NONPRIV_ACCESS_INVALID REG_FIELD_PREP(RING_FORCE_TO_NONPRIV_ACCESS_MASK, 3)
#define RING_FORCE_TO_NONPRIV_ADDRESS_MASK REG_GENMASK(25, 2)
#define RING_FORCE_TO_NONPRIV_RANGE_MASK REG_GENMASK(1, 0)
#define RING_FORCE_TO_NONPRIV_RANGE_1 REG_FIELD_PREP(RING_FORCE_TO_NONPRIV_RANGE_MASK, 0)
#define RING_FORCE_TO_NONPRIV_RANGE_4 REG_FIELD_PREP(RING_FORCE_TO_NONPRIV_RANGE_MASK, 1)
#define RING_FORCE_TO_NONPRIV_RANGE_16 REG_FIELD_PREP(RING_FORCE_TO_NONPRIV_RANGE_MASK, 2)
#define RING_FORCE_TO_NONPRIV_RANGE_64 REG_FIELD_PREP(RING_FORCE_TO_NONPRIV_RANGE_MASK, 3)
#define RING_FORCE_TO_NONPRIV_MASK_VALID (RING_FORCE_TO_NONPRIV_RANGE_MASK | \
RING_FORCE_TO_NONPRIV_ACCESS_MASK | \
RING_FORCE_TO_NONPRIV_DENY)
#define RING_MAX_NONPRIV_SLOTS 12
#define RING_EXECLIST_SQ_CONTENTS_LO(base) XE_REG((base) + 0x510)
#define RING_EXECLIST_SQ_CONTENTS_HI(base) XE_REG((base) + 0x510 + 4)
#define RING_EXECLIST_CONTROL(base) XE_REG((base) + 0x550)
#define EL_CTRL_LOAD REG_BIT(0)
#define CS_CHICKEN1(base) XE_REG((base) + 0x580, XE_REG_OPTION_MASKED)
#define PREEMPT_GPGPU_LEVEL(hi, lo) (((hi) << 2) | ((lo) << 1))
#define PREEMPT_GPGPU_MID_THREAD_LEVEL PREEMPT_GPGPU_LEVEL(0, 0)
#define PREEMPT_GPGPU_THREAD_GROUP_LEVEL PREEMPT_GPGPU_LEVEL(0, 1)
#define PREEMPT_GPGPU_COMMAND_LEVEL PREEMPT_GPGPU_LEVEL(1, 0)
#define PREEMPT_GPGPU_LEVEL_MASK PREEMPT_GPGPU_LEVEL(1, 1)
#define PREEMPT_3D_OBJECT_LEVEL REG_BIT(0)
#define CS_GPR_DATA(base, n) XE_REG((base) + 0x600 + (n) * 4)
#define CS_GPR_REG(base, n) CS_GPR_DATA((base), (n) * 2)
#define CS_GPR_REG_UDW(base, n) CS_GPR_DATA((base), (n) * 2 + 1)
#define VDBOX_CGCTL3F08(base) XE_REG((base) + 0x3f08)
#define CG3DDISHRS_CLKGATE_DIS REG_BIT(5)
#define VDBOX_CGCTL3F10(base) XE_REG((base) + 0x3f10)
#define IECPUNIT_CLKGATE_DIS REG_BIT(22)
#define RAMDFTUNIT_CLKGATE_DIS REG_BIT(9)
#define VDBOX_CGCTL3F18(base) XE_REG((base) + 0x3f18)
#define ALNUNIT_CLKGATE_DIS REG_BIT(13)
#define VDBOX_CGCTL3F1C(base) XE_REG((base) + 0x3f1c)
#define MFXPIPE_CLKGATE_DIS REG_BIT(3)
#endif
@@ -0,0 +1,29 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2025 Intel Corporation
*/
#ifndef _XE_EU_STALL_REGS_H_
#define _XE_EU_STALL_REGS_H_
#include "regs/xe_reg_defs.h"
#define XEHPC_EUSTALL_BASE XE_REG_MCR(0xe520)
#define XEHPC_EUSTALL_BASE_BUF_ADDR REG_GENMASK(31, 6)
#define XEHPC_EUSTALL_BASE_XECORE_BUF_SZ REG_GENMASK(5, 3)
#define XEHPC_EUSTALL_BASE_ENABLE_SAMPLING REG_BIT(1)
#define XEHPC_EUSTALL_BASE_UPPER XE_REG_MCR(0xe524)
#define XEHPC_EUSTALL_REPORT XE_REG_MCR(0xe528, XE_REG_OPTION_MASKED)
#define XEHPC_EUSTALL_REPORT_WRITE_PTR_MASK REG_GENMASK(15, 2)
#define XEHPC_EUSTALL_REPORT_OVERFLOW_DROP REG_BIT(1)
#define XEHPC_EUSTALL_REPORT1 XE_REG_MCR(0xe52c, XE_REG_OPTION_MASKED)
#define XEHPC_EUSTALL_REPORT1_READ_PTR_MASK REG_GENMASK(15, 2)
#define XEHPC_EUSTALL_CTRL XE_REG_MCR(0xe53c, XE_REG_OPTION_MASKED)
#define EUSTALL_MOCS REG_GENMASK(9, 3)
#define EUSTALL_SAMPLE_RATE REG_GENMASK(2, 0)
#endif
@@ -0,0 +1,58 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_GSC_REGS_H_
#define _XE_GSC_REGS_H_
#include <linux/compiler.h>
#include <linux/types.h>
#include "regs/xe_reg_defs.h"
/* Definitions of GSC H/W registers, bits, etc */
#define BMG_GSC_HECI1_BASE 0x373000
#define MTL_GSC_HECI1_BASE 0x00116000
#define MTL_GSC_HECI2_BASE 0x00117000
#define DG1_GSC_HECI2_BASE 0x00259000
#define PVC_GSC_HECI2_BASE 0x00285000
#define DG2_GSC_HECI2_BASE 0x00374000
#define HECI_H_CSR(base) XE_REG((base) + 0x4)
#define HECI_H_CSR_IE REG_BIT(0)
#define HECI_H_CSR_IS REG_BIT(1)
#define HECI_H_CSR_IG REG_BIT(2)
#define HECI_H_CSR_RDY REG_BIT(3)
#define HECI_H_CSR_RST REG_BIT(4)
/*
* The FWSTS register values are FW defined and can be different between
* HECI1 and HECI2
*/
#define HECI_FWSTS1(base) XE_REG((base) + 0xc40)
#define HECI1_FWSTS1_CURRENT_STATE REG_GENMASK(3, 0)
#define HECI1_FWSTS1_CURRENT_STATE_RESET 0
#define HECI1_FWSTS1_PROXY_STATE_NORMAL 5
#define HECI1_FWSTS1_INIT_COMPLETE REG_BIT(9)
#define HECI_FWSTS2(base) XE_REG((base) + 0xc48)
#define HECI_FWSTS3(base) XE_REG((base) + 0xc60)
#define HECI_FWSTS4(base) XE_REG((base) + 0xc64)
#define HECI_FWSTS5(base) XE_REG((base) + 0xc68)
#define HECI1_FWSTS5_HUC_AUTH_DONE REG_BIT(19)
#define HECI_FWSTS6(base) XE_REG((base) + 0xc6c)
#define HECI_H_GS1(base) XE_REG((base) + 0xc4c)
#define HECI_H_GS1_ER_PREP REG_BIT(0)
#define GSCI_TIMER_STATUS XE_REG(0x11ca28)
#define GSCI_TIMER_STATUS_VALUE REG_GENMASK(1, 0)
#define GSCI_TIMER_STATUS_RESET_IN_PROGRESS 0
#define GSCI_TIMER_STATUS_TIMER_EXPIRED 1
#define GSCI_TIMER_STATUS_RESET_COMPLETE 2
#define GSCI_TIMER_STATUS_OUT_OF_RESET 3
#endif
@@ -0,0 +1,666 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_GT_REGS_H_
#define _XE_GT_REGS_H_
#include "regs/xe_reg_defs.h"
/*
* The GSI register range [0x0 - 0x40000) is replicated at a higher offset
* for the media GT. xe_mmio and xe_gt_mcr functions will automatically
* translate offsets by MEDIA_GT_GSI_OFFSET when operating on the media GT.
*/
#define MEDIA_GT_GSI_OFFSET 0x380000
#define MEDIA_GT_GSI_LENGTH 0x40000
/* MTL workpoint reg to get core C state and actual freq of 3D, SAMedia */
#define MTL_MIRROR_TARGET_WP1 XE_REG(0xc60)
#define MTL_CAGF_MASK REG_GENMASK(8, 0)
#define MTL_CC_MASK REG_GENMASK(12, 9)
#define MTL_CRST 0xf
/* RPM unit config (Gen8+) */
#define RPM_CONFIG0 XE_REG(0xd00)
#define RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_MASK REG_GENMASK(5, 3)
#define RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_24_MHZ 0
#define RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_19_2_MHZ 1
#define RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_38_4_MHZ 2
#define RPM_CONFIG0_CRYSTAL_CLOCK_FREQ_25_MHZ 3
#define RPM_CONFIG0_CTC_SHIFT_PARAMETER_MASK REG_GENMASK(2, 1)
#define FORCEWAKE_ACK_MEDIA_VDBOX(n) XE_REG(0xd50 + (n) * 4)
#define FORCEWAKE_ACK_MEDIA_VEBOX(n) XE_REG(0xd70 + (n) * 4)
#define FORCEWAKE_ACK_RENDER XE_REG(0xd84)
#define GMD_ID XE_REG(0xd8c)
#define GMD_ID_ARCH_MASK REG_GENMASK(31, 22)
#define GMD_ID_RELEASE_MASK REG_GENMASK(21, 14)
/*
* Spec defines these bits as "Reserved", but then make them assume some
* meaning that depends on the ARCH. To avoid any confusion, call them
* SUBIP_FLAG_MASK.
*/
#define GMD_ID_SUBIP_FLAG_MASK REG_GENMASK(13, 6)
#define GMD_ID_REVID REG_GENMASK(5, 0)
#define FORCEWAKE_ACK_GSC XE_REG(0xdf8)
#define FORCEWAKE_ACK_GT_MTL XE_REG(0xdfc)
#define STEER_SEMAPHORE XE_REG(0xfd0)
#define MTL_MCR_SELECTOR XE_REG(0xfd4)
#define SF_MCR_SELECTOR XE_REG(0xfd8)
#define MCR_SELECTOR XE_REG(0xfdc)
#define GAM_MCR_SELECTOR XE_REG(0xfe0)
#define MCR_MULTICAST REG_BIT(31)
#define MCR_SLICE_MASK REG_GENMASK(30, 27)
#define MCR_SLICE(slice) REG_FIELD_PREP(MCR_SLICE_MASK, slice)
#define MCR_SUBSLICE_MASK REG_GENMASK(26, 24)
#define MCR_SUBSLICE(subslice) REG_FIELD_PREP(MCR_SUBSLICE_MASK, subslice)
#define MTL_MCR_GROUPID REG_GENMASK(12, 8)
#define MTL_MCR_INSTANCEID REG_GENMASK(3, 0)
#define PS_INVOCATION_COUNT XE_REG(0x2348)
#define XELP_GLOBAL_MOCS(i) XE_REG(0x4000 + (i) * 4)
#define XEHP_GLOBAL_MOCS(i) XE_REG_MCR(0x4000 + (i) * 4)
#define LE_SSE_MASK REG_GENMASK(18, 17)
#define LE_SSE(value) REG_FIELD_PREP(LE_SSE_MASK, value)
#define LE_COS_MASK REG_GENMASK(16, 15)
#define LE_SCF_MASK REG_BIT(14)
#define LE_SCF(value) REG_FIELD_PREP(LE_SCF_MASK, value)
#define LE_PFM_MASK REG_GENMASK(13, 11)
#define LE_PFM(value) REG_FIELD_PREP(LE_PFM_MASK, value)
#define LE_SCC_MASK REG_GENMASK(10, 8)
#define LE_SCC(value) REG_FIELD_PREP(LE_SCC_MASK, value)
#define LE_RSC_MASK REG_BIT(7)
#define LE_RSC(value) REG_FIELD_PREP(LE_RSC_MASK, value)
#define LE_AOM_MASK REG_BIT(6)
#define LE_AOM(value) REG_FIELD_PREP(LE_AOM_MASK, value)
#define LE_LRUM_MASK REG_GENMASK(5, 4)
#define LE_LRUM(value) REG_FIELD_PREP(LE_LRUM_MASK, value)
#define LE_TGT_CACHE_MASK REG_GENMASK(3, 2)
#define LE_TGT_CACHE(value) REG_FIELD_PREP(LE_TGT_CACHE_MASK, value)
#define LE_CACHEABILITY_MASK REG_GENMASK(1, 0)
#define LE_CACHEABILITY(value) REG_FIELD_PREP(LE_CACHEABILITY_MASK, value)
#define STATELESS_COMPRESSION_CTRL XE_REG_MCR(0x4148)
#define UNIFIED_COMPRESSION_FORMAT REG_GENMASK(3, 0)
#define XE2_GAMREQSTRM_CTRL XE_REG_MCR(0x4194)
#define EN_CMP_1WCOH REG_BIT(15)
#define CG_DIS_CNTLBUS REG_BIT(6)
#define CCS_AUX_INV XE_REG(0x4208)
#define VD0_AUX_INV XE_REG(0x4218)
#define VE0_AUX_INV XE_REG(0x4238)
#define VE1_AUX_INV XE_REG(0x42b8)
#define AUX_INV REG_BIT(0)
#define GAMSTLB_CTRL XE_REG_MCR(0x477c)
#define DIS_PEND_GPA_LINK REG_BIT(13)
#define GAMSTLB_CTRL2 XE_REG_MCR(0x4788)
#define STLB_SINGLE_BANK_MODE REG_BIT(11)
#define XE2_LMEM_CFG XE_REG(0x48b0)
#define XE2_GAMWALK_CTRL 0x47e4
#define XE2_GAMWALK_CTRL_MEDIA XE_REG(XE2_GAMWALK_CTRL + MEDIA_GT_GSI_OFFSET)
#define XE2_GAMWALK_CTRL_3D XE_REG_MCR(XE2_GAMWALK_CTRL)
#define EN_CMP_1WCOH_GW REG_BIT(14)
#define MMIOATSREQLIMIT_GAM_WALK_3D XE_REG_MCR(0x47f8)
#define DIS_ATS_WRONLY_PG REG_BIT(18)
#define XEHP_FLAT_CCS_BASE_ADDR XE_REG_MCR(0x4910)
#define XEHP_FLAT_CCS_PTR REG_GENMASK(31, 8)
#define WM_CHICKEN3 XE_REG_MCR(0x5588, XE_REG_OPTION_MASKED)
#define HIZ_PLANE_COMPRESSION_DIS REG_BIT(10)
#define CHICKEN_RASTER_1 XE_REG_MCR(0x6204, XE_REG_OPTION_MASKED)
#define DIS_SF_ROUND_NEAREST_EVEN REG_BIT(8)
#define DIS_CLIP_NEGATIVE_BOUNDING_BOX REG_BIT(6)
#define CHICKEN_RASTER_2 XE_REG_MCR(0x6208, XE_REG_OPTION_MASKED)
#define TBIMR_FAST_CLIP REG_BIT(5)
#define FF_MODE XE_REG_MCR(0x6210)
#define DIS_TE_AUTOSTRIP REG_BIT(31)
#define VS_HIT_MAX_VALUE_MASK REG_GENMASK(25, 20)
#define DIS_MESH_PARTIAL_AUTOSTRIP REG_BIT(16)
#define DIS_MESH_AUTOSTRIP REG_BIT(15)
#define DIS_TE_PATCH_CTRL REG_BIT(4)
#define VFLSKPD XE_REG_MCR(0x62a8, XE_REG_OPTION_MASKED)
#define DIS_PARTIAL_AUTOSTRIP REG_BIT(9)
#define DIS_AUTOSTRIP REG_BIT(6)
#define DIS_OVER_FETCH_CACHE REG_BIT(1)
#define DIS_MULT_MISS_RD_SQUASH REG_BIT(0)
#define FF_MODE2 XE_REG(0x6604)
#define XEHP_FF_MODE2 XE_REG_MCR(0x6604)
#define FF_MODE2_GS_TIMER_MASK REG_GENMASK(31, 24)
#define FF_MODE2_GS_TIMER_224 REG_FIELD_PREP(FF_MODE2_GS_TIMER_MASK, 224)
#define FF_MODE2_TDS_TIMER_MASK REG_GENMASK(23, 16)
#define FF_MODE2_TDS_TIMER_128 REG_FIELD_PREP(FF_MODE2_TDS_TIMER_MASK, 4)
#define XEHPG_INSTDONE_GEOM_SVGUNIT XE_REG_MCR(0x666c)
#define CACHE_MODE_1 XE_REG_MCR(0x7004, XE_REG_OPTION_MASKED)
#define MSAA_OPTIMIZATION_REDUC_DISABLE REG_BIT(11)
#define COMMON_SLICE_CHICKEN1 XE_REG(0x7010, XE_REG_OPTION_MASKED)
#define XEHP_COMMON_SLICE_CHICKEN1 XE_REG_MCR(0x7010, XE_REG_OPTION_MASKED)
#define DISABLE_BOTTOM_CLIP_RECTANGLE_TEST REG_BIT(14)
#define HIZ_CHICKEN XE_REG(0x7018, XE_REG_OPTION_MASKED)
#define DG1_HZ_READ_SUPPRESSION_OPTIMIZATION_DISABLE REG_BIT(14)
#define HZ_DEPTH_TEST_LE_GE_OPT_DISABLE REG_BIT(13)
#define XEHP_PSS_MODE2 XE_REG_MCR(0x703c, XE_REG_OPTION_MASKED)
#define SCOREBOARD_STALL_FLUSH_CONTROL REG_BIT(5)
#define XEHP_PSS_CHICKEN XE_REG_MCR(0x7044, XE_REG_OPTION_MASKED)
#define FLSH_IGNORES_PSD REG_BIT(10)
#define FD_END_COLLECT REG_BIT(5)
#define SC_INSTDONE XE_REG(0x7100)
#define SC_INSTDONE_EXTRA XE_REG(0x7104)
#define SC_INSTDONE_EXTRA2 XE_REG(0x7108)
#define XEHPG_SC_INSTDONE XE_REG_MCR(0x7100)
#define XEHPG_SC_INSTDONE_EXTRA XE_REG_MCR(0x7104)
#define XEHPG_SC_INSTDONE_EXTRA2 XE_REG_MCR(0x7108)
#define COMMON_SLICE_CHICKEN4 XE_REG(0x7300, XE_REG_OPTION_MASKED)
#define XEHP_COMMON_SLICE_CHICKEN4 XE_REG_MCR(0x7300, XE_REG_OPTION_MASKED)
#define SBE_PUSH_CONSTANT_BEHIND_FIX_ENABLE REG_BIT(12)
#define DISABLE_TDC_LOAD_BALANCING_CALC REG_BIT(6)
#define HW_FILTERING REG_BIT(5)
#define COMMON_SLICE_CHICKEN3 XE_REG(0x7304, XE_REG_OPTION_MASKED)
#define XEHP_COMMON_SLICE_CHICKEN3 XE_REG_MCR(0x7304, XE_REG_OPTION_MASKED)
#define DISABLE_STATE_CACHE_PERF_FIX REG_BIT(13)
#define DG1_FLOAT_POINT_BLEND_OPT_STRICT_MODE_EN REG_BIT(12)
#define XEHP_DUAL_SIMD8_SEQ_MERGE_DISABLE REG_BIT(12)
#define BLEND_EMB_FIX_DISABLE_IN_RCC REG_BIT(11)
#define DISABLE_CPS_AWARE_COLOR_PIPE REG_BIT(9)
#define XEHP_SLICE_COMMON_ECO_CHICKEN1 XE_REG_MCR(0x731c, XE_REG_OPTION_MASKED)
#define MSC_MSAA_REODER_BUF_BYPASS_DISABLE REG_BIT(14)
#define FAST_CLEAR_VALIGN_FIX REG_BIT(13)
#define XE2LPM_CCCHKNREG1 XE_REG(0x82a8)
#define VF_PREEMPTION XE_REG(0x83a4, XE_REG_OPTION_MASKED)
#define PREEMPTION_VERTEX_COUNT REG_GENMASK(15, 0)
#define VF_SCRATCHPAD XE_REG(0x83a8, XE_REG_OPTION_MASKED)
#define XE2_VFG_TED_CREDIT_INTERFACE_DISABLE REG_BIT(13)
#define VFG_PREEMPTION_CHICKEN XE_REG(0x83b4, XE_REG_OPTION_MASKED)
#define POLYGON_TRIFAN_LINELOOP_DISABLE REG_BIT(4)
#define SQCNT1 XE_REG_MCR(0x8718)
#define XELPMP_SQCNT1 XE_REG(0x8718)
#define SQCNT1_PMON_ENABLE REG_BIT(30)
#define SQCNT1_OABPC REG_BIT(29)
#define ENFORCE_RAR REG_BIT(23)
#define XEHP_SQCM XE_REG_MCR(0x8724)
#define EN_32B_ACCESS REG_BIT(30)
#define XE2_FLAT_CCS_BASE_RANGE_LOWER XE_REG_MCR(0x8800)
#define XE2_FLAT_CCS_ENABLE REG_BIT(0)
#define XE2_FLAT_CCS_BASE_LOWER_ADDR_MASK REG_GENMASK(31, 6)
#define XE2_FLAT_CCS_BASE_RANGE_UPPER XE_REG_MCR(0x8804)
#define XE2_FLAT_CCS_BASE_UPPER_ADDR_MASK REG_GENMASK(7, 0)
#define GSCPSMI_BASE XE_REG(0x880c)
#define CCCHKNREG1 XE_REG_MCR(0x8828)
#define L3CMPCTRL REG_BIT(23)
#define ENCOMPPERFFIX REG_BIT(18)
/* Fuse readout registers for GT */
#define XEHP_FUSE4 XE_REG(0x9114)
#define CFEG_WMTP_DISABLE REG_BIT(20)
#define CCS_EN_MASK REG_GENMASK(19, 16)
#define GT_L3_EXC_MASK REG_GENMASK(6, 4)
#define MIRROR_FUSE3 XE_REG(0x9118)
#define XE2_NODE_ENABLE_MASK REG_GENMASK(31, 16)
#define L3BANK_PAIR_COUNT 4
#define XEHPC_GT_L3_MODE_MASK REG_GENMASK(7, 4)
#define XE2_GT_L3_MODE_MASK REG_GENMASK(7, 4)
#define L3BANK_MASK REG_GENMASK(3, 0)
#define XELP_GT_L3_MODE_MASK REG_GENMASK(7, 0)
/* on Xe_HP the same fuses indicates mslices instead of L3 banks */
#define MAX_MSLICES 4
#define MEML3_EN_MASK REG_GENMASK(3, 0)
#define MIRROR_FUSE1 XE_REG(0x911c)
#define FUSE2 XE_REG(0x9120)
#define PRODUCTION_HW REG_BIT(2)
#define MIRROR_L3BANK_ENABLE XE_REG(0x9130)
#define XE3_L3BANK_ENABLE REG_GENMASK(31, 0)
#define XELP_EU_ENABLE XE_REG(0x9134) /* "_DISABLE" on Xe_LP */
#define XELP_EU_MASK REG_GENMASK(7, 0)
#define XELP_GT_SLICE_ENABLE XE_REG(0x9138)
#define XELP_GT_GEOMETRY_DSS_ENABLE XE_REG(0x913c)
#define GT_VEBOX_VDBOX_DISABLE XE_REG(0x9140)
#define GT_VEBOX_DISABLE_MASK REG_GENMASK(19, 16)
#define GT_VDBOX_DISABLE_MASK REG_GENMASK(7, 0)
#define XEHP_GT_COMPUTE_DSS_ENABLE XE_REG(0x9144)
#define XEHPC_GT_COMPUTE_DSS_ENABLE_EXT XE_REG(0x9148)
#define XE2_GT_COMPUTE_DSS_2 XE_REG(0x914c)
#define XE2_GT_GEOMETRY_DSS_1 XE_REG(0x9150)
#define XE2_GT_GEOMETRY_DSS_2 XE_REG(0x9154)
#define XE3P_XPC_GT_GEOMETRY_DSS_3 XE_REG(0x915c)
#define XE3P_XPC_GT_COMPUTE_DSS_3 XE_REG(0x9160)
#define SERVICE_COPY_ENABLE XE_REG(0x9170)
#define FUSE_SERVICE_COPY_ENABLE_MASK REG_GENMASK(7, 0)
#define GDRST XE_REG(0x941c)
#define GRDOM_GUC REG_BIT(3)
#define GRDOM_FULL REG_BIT(0)
#define MISCCPCTL XE_REG(0x9424)
#define DOP_CLOCK_GATE_RENDER_ENABLE REG_BIT(1)
#define UNSLCGCTL9430 XE_REG(0x9430)
#define MSQDUNIT_CLKGATE_DIS REG_BIT(3)
#define UNSLICE_UNIT_LEVEL_CLKGATE XE_REG(0x9434)
#define VFUNIT_CLKGATE_DIS REG_BIT(20)
#define TSGUNIT_CLKGATE_DIS REG_BIT(17) /* XEHPSDV */
#define CG3DDISCFEG_CLKGATE_DIS REG_BIT(17) /* DG2 */
#define GAMEDIA_CLKGATE_DIS REG_BIT(11)
#define HSUNIT_CLKGATE_DIS REG_BIT(8)
#define VSUNIT_CLKGATE_DIS REG_BIT(3)
#define UNSLCGCTL9440 XE_REG(0x9440)
#define GAMTLBOACS_CLKGATE_DIS REG_BIT(28)
#define GAMTLBVDBOX5_CLKGATE_DIS REG_BIT(27)
#define GAMTLBVDBOX6_CLKGATE_DIS REG_BIT(26)
#define GAMTLBVDBOX3_CLKGATE_DIS REG_BIT(24)
#define GAMTLBVDBOX4_CLKGATE_DIS REG_BIT(23)
#define GAMTLBVDBOX7_CLKGATE_DIS REG_BIT(22)
#define GAMTLBVDBOX2_CLKGATE_DIS REG_BIT(21)
#define GAMTLBVDBOX0_CLKGATE_DIS REG_BIT(17)
#define GAMTLBKCR_CLKGATE_DIS REG_BIT(16)
#define GAMTLBGUC_CLKGATE_DIS REG_BIT(15)
#define GAMTLBBLT_CLKGATE_DIS REG_BIT(14)
#define GAMTLBVDBOX1_CLKGATE_DIS REG_BIT(6)
#define UNSLCGCTL9444 XE_REG(0x9444)
#define GAMTLBGFXA0_CLKGATE_DIS REG_BIT(30)
#define GAMTLBGFXA1_CLKGATE_DIS REG_BIT(29)
#define GAMTLBCOMPA0_CLKGATE_DIS REG_BIT(28)
#define GAMTLBCOMPA1_CLKGATE_DIS REG_BIT(27)
#define GAMTLBCOMPB0_CLKGATE_DIS REG_BIT(26)
#define GAMTLBCOMPB1_CLKGATE_DIS REG_BIT(25)
#define GAMTLBCOMPC0_CLKGATE_DIS REG_BIT(24)
#define GAMTLBCOMPC1_CLKGATE_DIS REG_BIT(23)
#define GAMTLBCOMPD0_CLKGATE_DIS REG_BIT(22)
#define GAMTLBCOMPD1_CLKGATE_DIS REG_BIT(21)
#define GAMTLBMERT_CLKGATE_DIS REG_BIT(20)
#define GAMTLBVEBOX3_CLKGATE_DIS REG_BIT(19)
#define GAMTLBVEBOX2_CLKGATE_DIS REG_BIT(18)
#define GAMTLBVEBOX1_CLKGATE_DIS REG_BIT(17)
#define GAMTLBVEBOX0_CLKGATE_DIS REG_BIT(16)
#define LTCDD_CLKGATE_DIS REG_BIT(10)
#define UNSLCGCTL9454 XE_REG(0x9454)
#define LSCFE_CLKGATE_DIS REG_BIT(4)
#define XEHP_SLICE_UNIT_LEVEL_CLKGATE XE_REG_MCR(0x94d4)
#define L3_CR2X_CLKGATE_DIS REG_BIT(17)
#define L3_CLKGATE_DIS REG_BIT(16)
#define NODEDSS_CLKGATE_DIS REG_BIT(12)
#define MSCUNIT_CLKGATE_DIS REG_BIT(10)
#define RCCUNIT_CLKGATE_DIS REG_BIT(7)
#define SARBUNIT_CLKGATE_DIS REG_BIT(5)
#define SBEUNIT_CLKGATE_DIS REG_BIT(4)
#define UNSLICE_UNIT_LEVEL_CLKGATE2 XE_REG(0x94e4)
#define VSUNIT_CLKGATE2_DIS REG_BIT(19)
#define SUBSLICE_UNIT_LEVEL_CLKGATE XE_REG_MCR(0x9524)
#define DSS_ROUTER_CLKGATE_DIS REG_BIT(28)
#define GWUNIT_CLKGATE_DIS REG_BIT(16)
#define SUBSLICE_UNIT_LEVEL_CLKGATE2 XE_REG_MCR(0x9528)
#define CPSSUNIT_CLKGATE_DIS REG_BIT(9)
#define SSMCGCTL9530 XE_REG_MCR(0x9530)
#define RTFUNIT_CLKGATE_DIS REG_BIT(18)
#define DFR_RATIO_EN_AND_CHICKEN XE_REG_MCR(0x9550)
#define DFR_DISABLE REG_BIT(9)
#define RPNSWREQ XE_REG(0xa008)
#define REQ_RATIO_MASK REG_GENMASK(31, 23)
#define RP_CONTROL XE_REG(0xa024)
#define RPSWCTL_MASK REG_GENMASK(10, 9)
#define RPSWCTL_ENABLE REG_FIELD_PREP(RPSWCTL_MASK, 2)
#define RPSWCTL_DISABLE REG_FIELD_PREP(RPSWCTL_MASK, 0)
#define RC_CONTROL XE_REG(0xa090)
#define RC_CTL_HW_ENABLE REG_BIT(31)
#define RC_CTL_TO_MODE REG_BIT(28)
#define RC_CTL_RC6_ENABLE REG_BIT(18)
#define RC_STATE XE_REG(0xa094)
#define RC_IDLE_HYSTERSIS XE_REG(0xa0ac)
#define MEDIA_POWERGATE_IDLE_HYSTERESIS XE_REG(0xa0c4)
#define RENDER_POWERGATE_IDLE_HYSTERESIS XE_REG(0xa0c8)
#define PMINTRMSK XE_REG(0xa168)
#define PMINTR_DISABLE_REDIRECT_TO_GUC REG_BIT(31)
#define ARAT_EXPIRED_INTRMSK REG_BIT(9)
#define FORCEWAKE_GT XE_REG(0xa188)
#define POWERGATE_ENABLE XE_REG(0xa210)
#define RENDER_POWERGATE_ENABLE REG_BIT(0)
#define MEDIA_POWERGATE_ENABLE REG_BIT(1)
#define MEDIA_SAMPLERS_POWERGATE_ENABLE REG_BIT(2)
#define VDN_HCP_POWERGATE_ENABLE(n) REG_BIT(3 + 2 * (n))
#define VDN_MFXVDENC_POWERGATE_ENABLE(n) REG_BIT(4 + 2 * (n))
#define FORCEWAKE_RENDER XE_REG(0xa278)
#define POWERGATE_DOMAIN_STATUS XE_REG(0xa2a0)
#define GSC_AWAKE_STATUS REG_BIT(8)
#define MEDIA_SLICE3_AWAKE_STATUS REG_BIT(4)
#define MEDIA_SLICE2_AWAKE_STATUS REG_BIT(3)
#define MEDIA_SLICE1_AWAKE_STATUS REG_BIT(2)
#define RENDER_AWAKE_STATUS REG_BIT(1)
#define MEDIA_SLICE0_AWAKE_STATUS REG_BIT(0)
#define MISC_STATUS_0 XE_REG(0xa500)
#define FORCEWAKE_MEDIA_VDBOX(n) XE_REG(0xa540 + (n) * 4)
#define FORCEWAKE_MEDIA_VEBOX(n) XE_REG(0xa560 + (n) * 4)
#define FORCEWAKE_GSC XE_REG(0xa618)
#define XELP_GARBCNTL XE_REG(0xb004)
#define XELP_BUS_HASH_CTL_BIT_EXC REG_BIT(7)
#define XEHPC_LNCFMISCCFGREG0 XE_REG_MCR(0xb01c, XE_REG_OPTION_MASKED)
#define XEHPC_OVRLSCCC REG_BIT(0)
#define LNCFCMOCS_REG_COUNT 32
#define XELP_LNCFCMOCS(i) XE_REG(0xb020 + (i) * 4)
#define XEHP_LNCFCMOCS(i) XE_REG_MCR(0xb020 + (i) * 4)
#define L3_UPPER_LKUP_MASK REG_BIT(23)
#define L3_UPPER_GLBGO_MASK REG_BIT(22)
#define L3_UPPER_IDX_CACHEABILITY_MASK REG_GENMASK(21, 20)
#define L3_UPPER_IDX_SCC_MASK REG_GENMASK(19, 17)
#define L3_UPPER_IDX_ESC_MASK REG_BIT(16)
#define L3_LKUP_MASK REG_BIT(7)
#define L3_LKUP(value) REG_FIELD_PREP(L3_LKUP_MASK, value)
#define L3_GLBGO_MASK REG_BIT(6)
#define L3_GLBGO(value) REG_FIELD_PREP(L3_GLBGO_MASK, value)
#define L3_CACHEABILITY_MASK REG_GENMASK(5, 4)
#define L3_CACHEABILITY(value) REG_FIELD_PREP(L3_CACHEABILITY_MASK, value)
#define L3_SCC_MASK REG_GENMASK(3, 1)
#define L3_SCC(value) REG_FIELD_PREP(L3_SCC_MASK, value)
#define L3_ESC_MASK REG_BIT(0)
#define L3_ESC(value) REG_FIELD_PREP(L3_ESC_MASK, value)
#define XEHP_L3NODEARBCFG XE_REG_MCR(0xb0b4)
#define XEHP_LNESPARE REG_BIT(19)
#define LSN_VC_REG2 XE_REG_MCR(0xb0c8)
#define LSN_LNI_WGT_MASK REG_GENMASK(31, 28)
#define LSN_LNI_WGT(value) REG_FIELD_PREP(LSN_LNI_WGT_MASK, value)
#define LSN_LNE_WGT_MASK REG_GENMASK(27, 24)
#define LSN_LNE_WGT(value) REG_FIELD_PREP(LSN_LNE_WGT_MASK, value)
#define LSN_DIM_X_WGT_MASK REG_GENMASK(23, 20)
#define LSN_DIM_X_WGT(value) REG_FIELD_PREP(LSN_DIM_X_WGT_MASK, value)
#define LSN_DIM_Y_WGT_MASK REG_GENMASK(19, 16)
#define LSN_DIM_Y_WGT(value) REG_FIELD_PREP(LSN_DIM_Y_WGT_MASK, value)
#define LSN_DIM_Z_WGT_MASK REG_GENMASK(15, 12)
#define LSN_DIM_Z_WGT(value) REG_FIELD_PREP(LSN_DIM_Z_WGT_MASK, value)
#define L3SQCREG2 XE_REG_MCR(0xb104)
#define L3_SQ_DISABLE_COAMA_2WAY_COH REG_BIT(30)
#define L3_SQ_DISABLE_COAMA REG_BIT(22)
#define COMPMEMRD256BOVRFETCHEN REG_BIT(20)
#define L3SQCREG3 XE_REG_MCR(0xb108)
#define COMPPWOVERFETCHEN REG_BIT(28)
#define SCRATCH3_LBCF XE_REG_MCR(0xb154)
#define RWFLUSHALLEN REG_BIT(17)
#define XEHP_L3SQCREG5 XE_REG_MCR(0xb158)
#define L3_PWM_TIMER_INIT_VAL_MASK REG_GENMASK(9, 0)
#define XEHP_L3SCQREG7 XE_REG_MCR(0xb188)
#define BLEND_FILL_CACHING_OPT_DIS REG_BIT(3)
#define XEHPC_L3CLOS_MASK(i) XE_REG_MCR(0xb194 + (i) * 8)
#define L2COMPUTESIDECTRL XE_REG_MCR(0xb1c0)
#define CECTRL REG_GENMASK(2, 1)
#define CECTRL_CENODATA_ALWAYS REG_FIELD_PREP(CECTRL, 0x0)
#define XE2_GLOBAL_INVAL XE_REG(0xb404)
#define XE2LPM_L3SQCREG2 XE_REG_MCR(0xb604)
#define XE2LPM_L3SQCREG3 XE_REG_MCR(0xb608)
#define XE2LPM_SCRATCH3_LBCF XE_REG_MCR(0xb654)
#define XE2LPM_L3SQCREG5 XE_REG_MCR(0xb658)
#define XE2_TDF_CTRL XE_REG(0xb418)
#define TRANSIENT_FLUSH_REQUEST REG_BIT(0)
#define XEHP_MERT_MOD_CTRL XE_REG_MCR(0xcf28)
#define RENDER_MOD_CTRL XE_REG_MCR(0xcf2c)
#define COMP_MOD_CTRL XE_REG_MCR(0xcf30)
#define XEHP_VDBX_MOD_CTRL XE_REG_MCR(0xcf34)
#define XELPMP_VDBX_MOD_CTRL XE_REG(0xcf34)
#define XEHP_VEBX_MOD_CTRL XE_REG_MCR(0xcf38)
#define XELPMP_VEBX_MOD_CTRL XE_REG(0xcf38)
#define FORCE_MISS_FTLB REG_BIT(3)
#define XEHP_GAMSTLB_CTRL XE_REG_MCR(0xcf4c)
#define BANK_HASH_MODE REG_GENMASK(27, 26)
#define BANK_HASH_4KB_MODE REG_FIELD_PREP(BANK_HASH_MODE, 0x3)
#define CONTROL_BLOCK_CLKGATE_DIS REG_BIT(12)
#define EGRESS_BLOCK_CLKGATE_DIS REG_BIT(11)
#define TAG_BLOCK_CLKGATE_DIS REG_BIT(7)
#define XEHP_GAMCNTRL_CTRL XE_REG_MCR(0xcf54)
#define INVALIDATION_BROADCAST_MODE_DIS REG_BIT(12)
#define GLOBAL_INVALIDATION_MODE REG_BIT(2)
#define LMEM_CFG XE_REG(0xcf58)
#define LMEM_EN REG_BIT(31)
#define LMTT_DIR_PTR REG_GENMASK(30, 0) /* in multiples of 64KB */
#define HALF_SLICE_CHICKEN5 XE_REG_MCR(0xe188, XE_REG_OPTION_MASKED)
#define DISABLE_SAMPLE_G_PERFORMANCE REG_BIT(0)
#define SAMPLER_INSTDONE XE_REG_MCR(0xe160)
#define ROW_INSTDONE XE_REG_MCR(0xe164)
#define SAMPLER_MODE XE_REG_MCR(0xe18c, XE_REG_OPTION_MASKED)
#define ENABLE_SMALLPL REG_BIT(15)
#define SMP_WAIT_FETCH_MERGING_COUNTER REG_GENMASK(11, 10)
#define SMP_FORCE_128B_OVERFETCH REG_FIELD_PREP(SMP_WAIT_FETCH_MERGING_COUNTER, 1)
#define SC_DISABLE_POWER_OPTIMIZATION_EBB REG_BIT(9)
#define SAMPLER_ENABLE_HEADLESS_MSG REG_BIT(5)
#define INDIRECT_STATE_BASE_ADDR_OVERRIDE REG_BIT(0)
#define HALF_SLICE_CHICKEN7 XE_REG_MCR(0xe194, XE_REG_OPTION_MASKED)
#define DG2_DISABLE_ROUND_ENABLE_ALLOW_FOR_SSLA REG_BIT(15)
#define CLEAR_OPTIMIZATION_DISABLE REG_BIT(6)
#define CACHE_MODE_SS XE_REG_MCR(0xe420, XE_REG_OPTION_MASKED)
#define DISABLE_ECC REG_BIT(5)
#define ENABLE_PREFETCH_INTO_IC REG_BIT(3)
#define ROW_CHICKEN4 XE_REG_MCR(0xe48c, XE_REG_OPTION_MASKED)
#define DISABLE_GRF_CLEAR REG_BIT(13)
#define XEHP_DIS_BBL_SYSPIPE REG_BIT(11)
#define DISABLE_TDL_PUSH REG_BIT(9)
#define DIS_PICK_2ND_EU REG_BIT(7)
#define DISABLE_HDR_PAST_PAYLOAD_HOLD_FIX REG_BIT(4)
#define THREAD_EX_ARB_MODE REG_GENMASK(3, 2)
#define THREAD_EX_ARB_MODE_RR_AFTER_DEP REG_FIELD_PREP(THREAD_EX_ARB_MODE, 0x2)
#define ROW_CHICKEN3 XE_REG_MCR(0xe49c, XE_REG_OPTION_MASKED)
#define XE2_EUPEND_CHK_FLUSH_DIS REG_BIT(14)
#define DIS_EU_GRF_POISON_TO_LSC REG_BIT(13)
#define DIS_FIX_EOT1_FLUSH REG_BIT(9)
#define TDL_TSL_CHICKEN XE_REG_MCR(0xe4c4, XE_REG_OPTION_MASKED)
#define STK_ID_RESTRICT REG_BIT(12)
#define SLM_WMTP_RESTORE REG_BIT(11)
#define RES_CHK_SPR_DIS REG_BIT(6)
#define TDL_TSL_CHICKEN2 XE_REG_MCR(0xe4cc, XE_REG_OPTION_MASKED)
#define TILEY_LOCALID REG_BIT(2)
#define ROW_CHICKEN XE_REG_MCR(0xe4f0, XE_REG_OPTION_MASKED)
#define UGM_BACKUP_MODE REG_BIT(13)
#define MDQ_ARBITRATION_MODE REG_BIT(12)
#define STALL_DOP_GATING_DISABLE REG_BIT(5)
#define EARLY_EOT_DIS REG_BIT(1)
#define ROW_CHICKEN2 XE_REG_MCR(0xe4f4, XE_REG_OPTION_MASKED)
#define DISABLE_READ_SUPPRESSION REG_BIT(15)
#define DISABLE_EARLY_READ REG_BIT(14)
#define ENABLE_LARGE_GRF_MODE REG_BIT(12)
#define PUSH_CONST_DEREF_HOLD_DIS REG_BIT(8)
#define DISABLE_TDL_SVHS_GATING REG_BIT(1)
#define DISABLE_DOP_GATING REG_BIT(0)
#define RT_CTRL XE_REG_MCR(0xe530)
#define DIS_NULL_QUERY REG_BIT(10)
#define EU_SYSTOLIC_LIC_THROTTLE_CTL_WITH_LOCK XE_REG_MCR(0xe534)
#define EU_SYSTOLIC_LIC_THROTTLE_CTL_LOCK_BIT REG_BIT(31)
#define XEHP_HDC_CHICKEN0 XE_REG_MCR(0xe5f0, XE_REG_OPTION_MASKED)
#define LSC_L1_FLUSH_CTL_3D_DATAPORT_FLUSH_EVENTS_MASK REG_GENMASK(13, 11)
#define DIS_ATOMIC_CHAINING_TYPED_WRITES REG_BIT(3)
#define TDL_CHICKEN XE_REG_MCR(0xe5f4, XE_REG_OPTION_MASKED)
#define BIT_APQ_OPT_DIS REG_BIT(14)
#define QID_WAIT_FOR_THREAD_NOT_RUN_DISABLE REG_BIT(12)
#define EUSTALL_PERF_SAMPLING_DISABLE REG_BIT(5)
#define LSC_CHICKEN_BIT_0 XE_REG_MCR(0xe7c8)
#define DISABLE_D8_D16_COASLESCE REG_BIT(30)
#define WR_REQ_CHAINING_DIS REG_BIT(26)
#define TGM_WRITE_EOM_FORCE REG_BIT(17)
#define FORCE_1_SUB_MESSAGE_PER_FRAGMENT REG_BIT(15)
#define SEQUENTIAL_ACCESS_UPGRADE_DISABLE REG_BIT(13)
#define LSC_CHICKEN_BIT_0_UDW XE_REG_MCR(0xe7c8 + 4)
#define UGM_FRAGMENT_THRESHOLD_TO_3 REG_BIT(58 - 32)
#define DIS_CHAIN_2XSIMD8 REG_BIT(55 - 32)
#define XE2_ALLOC_DPA_STARVE_FIX_DIS REG_BIT(47 - 32)
#define SAMPLER_LD_LSC_DISABLE REG_BIT(45 - 32)
#define ENABLE_SMP_LD_RENDER_SURFACE_CONTROL REG_BIT(44 - 32)
#define FORCE_SLM_FENCE_SCOPE_TO_TILE REG_BIT(42 - 32)
#define FORCE_UGM_FENCE_SCOPE_TO_TILE REG_BIT(41 - 32)
#define L3_128B_256B_WRT_DIS REG_BIT(40 - 32)
#define MAXREQS_PER_BANK REG_GENMASK(39 - 32, 37 - 32)
#define DISABLE_128B_EVICTION_COMMAND_UDW REG_BIT(36 - 32)
#define LSCFE_SAME_ADDRESS_ATOMICS_COALESCING_DISABLE REG_BIT(35 - 32)
#define ROW_CHICKEN5 XE_REG_MCR(0xe7f0, XE_REG_OPTION_MASKED)
#define CPSS_AWARE_DIS REG_BIT(3)
#define SARB_CHICKEN1 XE_REG_MCR(0xe90c)
#define COMP_CKN_IN REG_GENMASK(30, 29)
#define MAIN_GAMCTRL_MODE XE_REG(0xef00)
#define MAIN_GAMCTRL_QUEUE_SELECT REG_BIT(0)
#define RCU_MODE XE_REG(0x14800, XE_REG_OPTION_MASKED)
#define RCU_MODE_FIXED_SLICE_CCS_MODE REG_BIT(1)
#define RCU_MODE_CCS_ENABLE REG_BIT(0)
/*
* Total of 4 cslices, where each cslice is in the form:
* [0-3] CCS ID
* [4-6] RSVD
* [7] Disabled
*/
#define CCS_MODE XE_REG(0x14804, XE_REG_OPTION_MASKED)
#define CCS_MODE_CSLICE_0_3_MASK REG_GENMASK(11, 0) /* 3 bits per cslice */
#define CCS_MODE_CSLICE_MASK 0x7 /* CCS0-3 + rsvd */
#define CCS_MODE_CSLICE_WIDTH ilog2(CCS_MODE_CSLICE_MASK + 1)
#define CCS_MODE_CSLICE(cslice, ccs) \
((ccs) << ((cslice) * CCS_MODE_CSLICE_WIDTH))
#define FORCEWAKE_ACK_GT XE_REG(0x130044)
/* Applicable for all FORCEWAKE_DOMAIN and FORCEWAKE_ACK_DOMAIN regs */
#define FORCEWAKE_KERNEL 0
#define FORCEWAKE_MT(bit) BIT(bit)
#define FORCEWAKE_MT_MASK(bit) BIT((bit) + 16)
#define MTL_MEDIA_PERF_LIMIT_REASONS XE_REG(0x138030)
#define MTL_MEDIA_MC6 XE_REG(0x138048)
#define GT_CORE_STATUS XE_REG(0x138060)
#define RCN_MASK REG_GENMASK(2, 0)
#define GT_C0 0
#define GT_C6 3
#define GT_GFX_RC6_LOCKED XE_REG(0x138104)
#define GT_GFX_RC6 XE_REG(0x138108)
#define GT0_PERF_LIMIT_REASONS XE_REG(0x1381a8)
/* Common performance limit reason bits - available on all platforms */
#define GT0_PERF_LIMIT_REASONS_MASK 0xde3
#define PROCHOT_MASK REG_BIT(0)
#define THERMAL_LIMIT_MASK REG_BIT(1)
#define RATL_MASK REG_BIT(5)
#define VR_THERMALERT_MASK REG_BIT(6)
#define VR_TDC_MASK REG_BIT(7)
#define POWER_LIMIT_4_MASK REG_BIT(8)
#define POWER_LIMIT_1_MASK REG_BIT(10)
#define POWER_LIMIT_2_MASK REG_BIT(11)
/* Platform-specific performance limit reason bits - for Crescent Island */
#define CRI_PERF_LIMIT_REASONS_MASK 0xfdff
#define SOC_THERMAL_LIMIT_MASK REG_BIT(1)
#define MEM_THERMAL_MASK REG_BIT(2)
#define VR_THERMAL_MASK REG_BIT(3)
#define ICCMAX_MASK REG_BIT(4)
#define SOC_AVG_THERMAL_MASK REG_BIT(6)
#define FASTVMODE_MASK REG_BIT(7)
#define PSYS_PL1_MASK REG_BIT(12)
#define PSYS_PL2_MASK REG_BIT(13)
#define P0_FREQ_MASK REG_BIT(14)
#define PSYS_CRIT_MASK REG_BIT(15)
#define GT_PERF_STATUS XE_REG(0x1381b4)
#define VOLTAGE_MASK REG_GENMASK(10, 0)
#define SFC_DONE(n) XE_REG(0x1cc000 + (n) * 0x1000)
#endif
@@ -0,0 +1,42 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef _XE_GTT_DEFS_H_
#define _XE_GTT_DEFS_H_
#define XELPG_GGTT_PTE_PAT0 BIT_ULL(52)
#define XELPG_GGTT_PTE_PAT1 BIT_ULL(53)
/*
* Mask for PTE address bits [51:shift].
* shift is the lower address boundary of page.
*/
#define XE_PAGE_ADDR_MASK(shift) GENMASK_ULL(51, (shift))
#define GGTT_PTE_VFID GENMASK_ULL(11, 2)
#define GUC_GGTT_TOP 0xFEE00000
#define XELPG_PPGTT_PTE_PAT3 BIT_ULL(62)
#define XE2_PPGTT_PTE_PAT4 BIT_ULL(61)
#define XE_PPGTT_PDE_PDPE_PAT2 BIT_ULL(12)
#define XE_PPGTT_PTE_PAT2 BIT_ULL(7)
#define XE_PPGTT_PTE_PAT1 BIT_ULL(4)
#define XE_PPGTT_PTE_PAT0 BIT_ULL(3)
#define XE_PDE_PS_2M BIT_ULL(7)
#define XE_PDPE_PS_1G BIT_ULL(7)
#define XE_PDE_IPS_64K BIT_ULL(11)
#define XE_GGTT_PTE_DM BIT_ULL(1)
#define XE_USM_PPGTT_PTE_AE BIT_ULL(10)
#define XE_PPGTT_PTE_DM BIT_ULL(11)
#define XE_PDE_64K BIT_ULL(6)
#define XE_PTE_PS64 BIT_ULL(8)
#define XE_PTE_NULL BIT_ULL(9)
#define XE_PAGE_PRESENT BIT_ULL(0)
#define XE_PAGE_RW BIT_ULL(1)
#endif
@@ -0,0 +1,165 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2022 Intel Corporation
*/
#ifndef _XE_GUC_REGS_H_
#define _XE_GUC_REGS_H_
#include <linux/compiler.h>
#include <linux/types.h>
#include "regs/xe_reg_defs.h"
/* Definitions of GuC H/W registers, bits, etc */
#define DIST_DBS_POPULATED XE_REG(0xd08)
#define DOORBELLS_PER_SQIDI_MASK REG_GENMASK(23, 16)
#define SQIDIS_DOORBELL_EXIST_MASK REG_GENMASK(15, 0)
#define DRBREGL(x) XE_REG(0x1000 + (x) * 8)
#define DRB_VALID REG_BIT(0)
#define DRBREGU(x) XE_REG(0x1000 + (x) * 8 + 4)
#define GTCR XE_REG(0x4274)
#define GTCR_INVALIDATE REG_BIT(0)
#define GUC_ARAT_C6DIS XE_REG(0xa178)
#define GUC_STATUS XE_REG(0xc000)
#define GS_AUTH_STATUS_MASK REG_GENMASK(31, 30)
#define GS_AUTH_STATUS_BAD REG_FIELD_PREP(GS_AUTH_STATUS_MASK, 0x1)
#define GS_AUTH_STATUS_GOOD REG_FIELD_PREP(GS_AUTH_STATUS_MASK, 0x2)
#define GS_MIA_MASK REG_GENMASK(18, 16)
#define GS_MIA_CORE_STATE REG_FIELD_PREP(GS_MIA_MASK, 0x1)
#define GS_MIA_HALT_REQUESTED REG_FIELD_PREP(GS_MIA_MASK, 0x2)
#define GS_MIA_ISR_ENTRY REG_FIELD_PREP(GS_MIA_MASK, 0x4)
#define GS_UKERNEL_MASK REG_GENMASK(15, 8)
#define GS_BOOTROM_MASK REG_GENMASK(7, 1)
#define GS_BOOTROM_RSA_FAILED REG_FIELD_PREP(GS_BOOTROM_MASK, 0x50)
#define GS_BOOTROM_JUMP_PASSED REG_FIELD_PREP(GS_BOOTROM_MASK, 0x76)
#define GS_MIA_IN_RESET REG_BIT(0)
#define BOOT_HASH_CHK XE_REG(0xc010)
#define GUC_BOOT_UKERNEL_VALID REG_BIT(31)
#define GUC_HEADER_INFO XE_REG(0xc014)
#define GUC_WOPCM_SIZE XE_REG(0xc050)
#define GUC_WOPCM_SIZE_MASK REG_GENMASK(31, 12)
#define GUC_WOPCM_SIZE_LOCKED REG_BIT(0)
#define GUC_SHIM_CONTROL XE_REG(0xc064)
#define GUC_MOCS_INDEX_MASK REG_GENMASK(27, 24)
#define GUC_SHIM_WC_ENABLE REG_BIT(21)
#define GUC_ENABLE_MIA_CLOCK_GATING REG_BIT(15)
#define GUC_ENABLE_READ_CACHE_FOR_WOPCM_DATA REG_BIT(10)
#define GUC_ENABLE_READ_CACHE_FOR_SRAM_DATA REG_BIT(9)
#define GUC_MSGCH_ENABLE REG_BIT(4)
#define GUC_ENABLE_MIA_CACHING REG_BIT(2)
#define GUC_ENABLE_READ_CACHE_LOGIC REG_BIT(1)
#define GUC_DISABLE_SRAM_INIT_TO_ZEROES REG_BIT(0)
#define SOFT_SCRATCH(n) XE_REG(0xc180 + (n) * 4)
#define SOFT_SCRATCH_COUNT 16
#define HUC_KERNEL_LOAD_INFO XE_REG(0xc1dc)
#define HUC_LOAD_SUCCESSFUL REG_BIT(0)
#define UOS_RSA_SCRATCH(i) XE_REG(0xc200 + (i) * 4)
#define UOS_RSA_SCRATCH_COUNT 64
#define DMA_ADDR_0_LOW XE_REG(0xc300)
#define DMA_ADDR_0_HIGH XE_REG(0xc304)
#define DMA_ADDR_1_LOW XE_REG(0xc308)
#define DMA_ADDR_1_HIGH XE_REG(0xc30c)
#define DMA_ADDR_SPACE_MASK REG_GENMASK(20, 16)
#define DMA_ADDRESS_SPACE_WOPCM REG_FIELD_PREP(DMA_ADDR_SPACE_MASK, 7)
#define DMA_ADDRESS_SPACE_GGTT REG_FIELD_PREP(DMA_ADDR_SPACE_MASK, 8)
#define DMA_COPY_SIZE XE_REG(0xc310)
#define DMA_CTRL XE_REG(0xc314)
#define HUC_UKERNEL REG_BIT(9)
#define UOS_MOVE REG_BIT(4)
#define START_DMA REG_BIT(0)
#define DMA_GUC_WOPCM_OFFSET XE_REG(0xc340)
#define GUC_WOPCM_OFFSET_SHIFT 14
#define GUC_WOPCM_OFFSET_MASK REG_GENMASK(31, GUC_WOPCM_OFFSET_SHIFT)
#define HUC_LOADING_AGENT_GUC REG_BIT(1)
#define GUC_WOPCM_OFFSET_VALID REG_BIT(0)
#define GUC_SRAM_STATUS XE_REG(0xc398)
#define GUC_SRAM_HANDLING_MASK REG_GENMASK(8, 7)
#define GUC_MAX_IDLE_COUNT XE_REG(0xc3e4)
#define GUC_IDLE_FLOW_DISABLE REG_BIT(31)
#define GUC_PMTIMESTAMP_LO XE_REG(0xc3e8)
#define GUC_PMTIMESTAMP_HI XE_REG(0xc3ec)
#define GUC_SEND_INTERRUPT XE_REG(0xc4c8)
#define GUC_SEND_TRIGGER REG_BIT(0)
#define GUC_INTR_CHICKEN XE_REG(0xc50c)
#define DISABLE_SIGNALING_ENGINES REG_BIT(1)
#define GUC_BCS_RCS_IER XE_REG(0xc550)
#define GUC_VCS2_VCS1_IER XE_REG(0xc554)
#define GUC_WD_VECS_IER XE_REG(0xc558)
#define GUC_PM_P24C_IER XE_REG(0xc55c)
#define GUC_TLB_INV_CR XE_REG(0xcee8)
#define GUC_TLB_INV_CR_INVALIDATE REG_BIT(0)
#define HUC_STATUS2 XE_REG(0xd3b0)
#define HUC_FW_VERIFIED REG_BIT(7)
#define GT_PM_CONFIG XE_REG(0x13816c)
#define GT_DOORBELL_ENABLE REG_BIT(0)
#define GUC_HOST_INTERRUPT XE_REG(0x1901f0, XE_REG_OPTION_VF)
#define VF_SW_FLAG(n) XE_REG(0x190240 + (n) * 4, XE_REG_OPTION_VF)
#define VF_SW_FLAG_COUNT 4
#define MED_GUC_HOST_INTERRUPT XE_REG(0x190304, XE_REG_OPTION_VF)
#define MED_VF_SW_FLAG(n) XE_REG(0x190310 + (n) * 4, XE_REG_OPTION_VF)
#define MED_VF_SW_FLAG_COUNT 4
#define GUC_TLB_INV_CR XE_REG(0xcee8)
#define GUC_TLB_INV_CR_INVALIDATE REG_BIT(0)
#define PVC_GUC_TLB_INV_DESC0 XE_REG(0xcf7c)
#define PVC_GUC_TLB_INV_DESC0_VALID REG_BIT(0)
#define PVC_GUC_TLB_INV_DESC1 XE_REG(0xcf80)
#define PVC_GUC_TLB_INV_DESC1_INVALIDATE REG_BIT(6)
/* GuC Interrupt Vector */
#define GUC_INTR_GUC2HOST REG_BIT(15)
#define GUC_INTR_EXEC_ERROR REG_BIT(14)
#define GUC_INTR_DISPLAY_EVENT REG_BIT(13)
#define GUC_INTR_SEM_SIG REG_BIT(12)
#define GUC_INTR_IOMMU2GUC REG_BIT(11)
#define GUC_INTR_DOORBELL_RANG REG_BIT(10)
#define GUC_INTR_DMA_DONE REG_BIT(9)
#define GUC_INTR_FATAL_ERROR REG_BIT(8)
#define GUC_INTR_NOTIF_ERROR REG_BIT(7)
#define GUC_INTR_SW_INT_6 REG_BIT(6)
#define GUC_INTR_SW_INT_5 REG_BIT(5)
#define GUC_INTR_SW_INT_4 REG_BIT(4)
#define GUC_INTR_SW_INT_3 REG_BIT(3)
#define GUC_INTR_SW_INT_2 REG_BIT(2)
#define GUC_INTR_SW_INT_1 REG_BIT(1)
#define GUC_INTR_SW_INT_0 REG_BIT(0)
#define GUC_NUM_DOORBELLS 256
/* format of the HW-monitored doorbell cacheline */
struct guc_doorbell_info {
u32 db_status;
#define GUC_DOORBELL_DISABLED 0
#define GUC_DOORBELL_ENABLED 1
u32 cookie;
u32 reserved[14];
} __packed;
#endif
@@ -0,0 +1,88 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2025 Intel Corporation
*/
#ifndef _XE_HW_ERROR_REGS_H_
#define _XE_HW_ERROR_REGS_H_
#define HEC_UNCORR_ERR_STATUS(base) XE_REG((base) + 0x118)
#define UNCORR_FW_REPORTED_ERR REG_BIT(6)
#define HEC_UNCORR_FW_ERR_DW0(base) XE_REG((base) + 0x124)
#define ERR_STAT_GT_COR 0x100160
#define EU_GRF_COR_ERR REG_BIT(15)
#define EU_IC_COR_ERR REG_BIT(14)
#define SLM_COR_ERR REG_BIT(13)
#define GUC_COR_ERR REG_BIT(1)
#define ERR_STAT_GT_NONFATAL 0x100164
#define ERR_STAT_GT_FATAL 0x100168
#define EU_GRF_FAT_ERR REG_BIT(15)
#define SLM_FAT_ERR REG_BIT(13)
#define GUC_FAT_ERR REG_BIT(6)
#define FPU_FAT_ERR REG_BIT(3)
#define ERR_STAT_GT_REG(x) XE_REG(_PICK_EVEN((x), \
ERR_STAT_GT_COR, \
ERR_STAT_GT_NONFATAL))
#define PVC_COR_ERR_MASK (GUC_COR_ERR | SLM_COR_ERR | \
EU_IC_COR_ERR | EU_GRF_COR_ERR)
#define PVC_FAT_ERR_MASK (FPU_FAT_ERR | GUC_FAT_ERR | \
EU_GRF_FAT_ERR | SLM_FAT_ERR)
#define DEV_ERR_STAT_NONFATAL 0x100178
#define DEV_ERR_STAT_CORRECTABLE 0x10017c
#define DEV_ERR_STAT_REG(x) XE_REG(_PICK_EVEN((x), \
DEV_ERR_STAT_CORRECTABLE, \
DEV_ERR_STAT_NONFATAL))
#define XE_CSC_ERROR 17
#define XE_SOC_ERROR 16
#define XE_GT_ERROR 0
#define ERR_STAT_GT_FATAL_VECTOR_0 0x100260
#define ERR_STAT_GT_FATAL_VECTOR_1 0x100264
#define ERR_STAT_GT_FATAL_VECTOR_REG(x) XE_REG(_PICK_EVEN((x), \
ERR_STAT_GT_FATAL_VECTOR_0, \
ERR_STAT_GT_FATAL_VECTOR_1))
#define ERR_STAT_GT_COR_VECTOR_0 0x1002a0
#define ERR_STAT_GT_COR_VECTOR_1 0x1002a4
#define ERR_STAT_GT_COR_VECTOR_REG(x) XE_REG(_PICK_EVEN((x), \
ERR_STAT_GT_COR_VECTOR_0, \
ERR_STAT_GT_COR_VECTOR_1))
#define ERR_STAT_GT_VECTOR_REG(hw_err, x) (hw_err == HARDWARE_ERROR_CORRECTABLE ? \
ERR_STAT_GT_COR_VECTOR_REG(x) : \
ERR_STAT_GT_FATAL_VECTOR_REG(x))
#define SOC_PVC_MASTER_BASE 0x282000
#define SOC_PVC_SLAVE_BASE 0x283000
#define SOC_GCOERRSTS 0x200
#define SOC_GNFERRSTS 0x210
#define SOC_GLOBAL_ERR_STAT_REG(base, x) XE_REG(_PICK_EVEN((x), \
(base) + SOC_GCOERRSTS, \
(base) + SOC_GNFERRSTS))
#define SOC_SLAVE_IEH REG_BIT(1)
#define SOC_IEH0_LOCAL_ERR_STATUS REG_BIT(0)
#define SOC_IEH1_LOCAL_ERR_STATUS REG_BIT(0)
#define SOC_GSYSEVTCTL 0x264
#define SOC_GSYSEVTCTL_REG(master, slave, x) XE_REG(_PICK_EVEN((x), \
(master) + SOC_GSYSEVTCTL, \
(slave) + SOC_GSYSEVTCTL))
#define SOC_LERRUNCSTS 0x280
#define SOC_LERRCORSTS 0x294
#define SOC_LOCAL_ERR_STAT_REG(base, hw_err) XE_REG(hw_err == HARDWARE_ERROR_CORRECTABLE ? \
(base) + SOC_LERRCORSTS : \
(base) + SOC_LERRUNCSTS)
#endif
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
#ifndef _XE_I2C_REGS_H_
#define _XE_I2C_REGS_H_
#include <linux/pci_regs.h>
#include "xe_reg_defs.h"
#include "xe_regs.h"
#define I2C_BRIDGE_OFFSET (SOC_BASE + 0xd9000)
#define I2C_CONFIG_SPACE_OFFSET (SOC_BASE + 0xf6000)
#define I2C_MEM_SPACE_OFFSET (SOC_BASE + 0xf7400)
#define REG_SG_REMAP_ADDR_PREFIX XE_REG(SOC_BASE + 0x0164)
#define REG_SG_REMAP_ADDR_POSTFIX XE_REG(SOC_BASE + 0x0168)
#define I2C_BRIDGE_PCICFGCTL XE_REG(I2C_BRIDGE_OFFSET + 0x200)
#define ACPI_INTR_EN REG_BIT(1)
#define I2C_CONFIG_CMD XE_REG(I2C_CONFIG_SPACE_OFFSET + PCI_COMMAND)
#define I2C_CONFIG_PMCSR XE_REG(I2C_CONFIG_SPACE_OFFSET + 0x84)
#endif /* _XE_I2C_REGS_H_ */
@@ -0,0 +1,98 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef _XE_IRQ_REGS_H_
#define _XE_IRQ_REGS_H_
#include "regs/xe_reg_defs.h"
#define PCU_IRQ_OFFSET 0x444e0
#define GU_MISC_IRQ_OFFSET 0x444f0
#define GU_MISC_GSE REG_BIT(27)
#define DG1_MSTR_TILE_INTR XE_REG(0x190008)
#define DG1_MSTR_IRQ REG_BIT(31)
#define DG1_MSTR_TILE(t) REG_BIT(t)
#define GFX_MSTR_IRQ XE_REG(0x190010, XE_REG_OPTION_VF)
#define MASTER_IRQ REG_BIT(31)
#define GU_MISC_IRQ REG_BIT(29)
#define ERROR_IRQ(x) REG_BIT(26 + (x))
#define DISPLAY_IRQ REG_BIT(16)
#define SOC_H2DMEMINT_IRQ REG_BIT(13)
#define I2C_IRQ REG_BIT(12)
#define SYSCTRL_IRQ REG_BIT(11)
#define GT_DW_IRQ(x) REG_BIT(x)
/*
* Note: Interrupt registers 1900xx are VF accessible only until version 12.50.
* On newer platforms, VFs are using memory-based interrupts instead.
* However, for simplicity we keep this XE_REG_OPTION_VF tag intact.
*/
#define GT_INTR_DW(x) XE_REG(0x190018 + ((x) * 4), XE_REG_OPTION_VF)
#define INTR_GSC REG_BIT(31)
#define INTR_GUC REG_BIT(25)
#define INTR_MGUC REG_BIT(24)
#define INTR_BCS8 REG_BIT(23)
#define INTR_BCS(x) REG_BIT(15 - (x))
#define INTR_CCS(x) REG_BIT(4 + (x))
#define INTR_RCS0 REG_BIT(0)
#define INTR_VECS(x) REG_BIT(31 - (x))
#define INTR_VCS(x) REG_BIT(x)
#define RENDER_COPY_INTR_ENABLE XE_REG(0x190030, XE_REG_OPTION_VF)
#define VCS_VECS_INTR_ENABLE XE_REG(0x190034, XE_REG_OPTION_VF)
#define GUC_SG_INTR_ENABLE XE_REG(0x190038, XE_REG_OPTION_VF)
#define ENGINE1_MASK REG_GENMASK(31, 16)
#define ENGINE0_MASK REG_GENMASK(15, 0)
#define GPM_WGBOXPERF_INTR_ENABLE XE_REG(0x19003c, XE_REG_OPTION_VF)
#define CRYPTO_RSVD_INTR_ENABLE XE_REG(0x190040)
#define GUNIT_GSC_INTR_ENABLE XE_REG(0x190044, XE_REG_OPTION_VF)
#define CCS_RSVD_INTR_ENABLE XE_REG(0x190048, XE_REG_OPTION_VF)
#define INTR_IDENTITY_REG(x) XE_REG(0x190060 + ((x) * 4), XE_REG_OPTION_VF)
#define INTR_DATA_VALID REG_BIT(31)
#define INTR_ENGINE_INSTANCE(x) REG_FIELD_GET(GENMASK(25, 20), x)
#define INTR_ENGINE_CLASS(x) REG_FIELD_GET(GENMASK(18, 16), x)
#define INTR_ENGINE_INTR(x) REG_FIELD_GET(GENMASK(15, 0), x)
#define OTHER_GUC_INSTANCE 0
#define OTHER_GSC_HECI2_INSTANCE 3
#define OTHER_KCR_INSTANCE 4
#define OTHER_GSC_INSTANCE 6
#define IIR_REG_SELECTOR(x) XE_REG(0x190070 + ((x) * 4), XE_REG_OPTION_VF)
#define RCS0_RSVD_INTR_MASK XE_REG(0x190090, XE_REG_OPTION_VF)
#define BCS_RSVD_INTR_MASK XE_REG(0x1900a0, XE_REG_OPTION_VF)
#define VCS0_VCS1_INTR_MASK XE_REG(0x1900a8, XE_REG_OPTION_VF)
#define VCS2_VCS3_INTR_MASK XE_REG(0x1900ac, XE_REG_OPTION_VF)
#define VCS4_VCS5_INTR_MASK XE_REG(0x1900b0, XE_REG_OPTION_VF)
#define VCS6_VCS7_INTR_MASK XE_REG(0x1900b4, XE_REG_OPTION_VF)
#define VECS0_VECS1_INTR_MASK XE_REG(0x1900d0, XE_REG_OPTION_VF)
#define VECS2_VECS3_INTR_MASK XE_REG(0x1900d4, XE_REG_OPTION_VF)
#define HECI2_RSVD_INTR_MASK XE_REG(0x1900e4)
#define GUC_SG_INTR_MASK XE_REG(0x1900e8, XE_REG_OPTION_VF)
#define GPM_WGBOXPERF_INTR_MASK XE_REG(0x1900ec, XE_REG_OPTION_VF)
#define CRYPTO_RSVD_INTR_MASK XE_REG(0x1900f0)
#define GUNIT_GSC_INTR_MASK XE_REG(0x1900f4, XE_REG_OPTION_VF)
#define CCS0_CCS1_INTR_MASK XE_REG(0x190100)
#define CCS2_CCS3_INTR_MASK XE_REG(0x190104)
#define XEHPC_BCS1_BCS2_INTR_MASK XE_REG(0x190110)
#define XEHPC_BCS3_BCS4_INTR_MASK XE_REG(0x190114)
#define XEHPC_BCS5_BCS6_INTR_MASK XE_REG(0x190118)
#define XEHPC_BCS7_BCS8_INTR_MASK XE_REG(0x19011c)
#define GT_WAIT_SEMAPHORE_INTERRUPT REG_BIT(11)
#define GT_CONTEXT_SWITCH_INTERRUPT REG_BIT(8)
#define GSC_ER_COMPLETE REG_BIT(5)
#define GT_FLUSH_COMPLETE_INTERRUPT REG_BIT(4)
#define GT_CS_MASTER_ERROR_INTERRUPT REG_BIT(3)
#define GT_COMPUTE_WALKER_INTERRUPT REG_BIT(2)
#define GT_MI_USER_INTERRUPT REG_BIT(0)
/* irqs for OTHER_KCR_INSTANCE */
#define KCR_PXP_STATE_TERMINATED_INTERRUPT REG_BIT(1)
#define KCR_APP_TERMINATED_PER_FW_REQ_INTERRUPT REG_BIT(2)
#define KCR_PXP_STATE_RESET_COMPLETE_INTERRUPT REG_BIT(3)
#endif
@@ -0,0 +1,46 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_LRC_LAYOUT_H_
#define _XE_LRC_LAYOUT_H_
#define CTX_CONTEXT_CONTROL (0x02 + 1)
#define CTX_RING_HEAD (0x04 + 1)
#define CTX_RING_TAIL (0x06 + 1)
#define CTX_RING_START (0x08 + 1)
#define CTX_RING_CTL (0x0a + 1)
#define CTX_BB_PER_CTX_PTR (0x12 + 1)
#define CTX_CS_INDIRECT_CTX (0x14 + 1)
#define CTX_CS_INDIRECT_CTX_OFFSET (0x16 + 1)
#define CTX_TIMESTAMP (0x22 + 1)
#define CTX_TIMESTAMP_UDW (0x24 + 1)
#define CTX_INDIRECT_RING_STATE (0x26 + 1)
#define CTX_ACC_CTR_THOLD (0x2a + 1)
#define CTX_ASID (0x2e + 1)
#define CTX_PDP0_UDW (0x30 + 1)
#define CTX_PDP0_LDW (0x32 + 1)
#define CTX_LRM_INT_MASK_ENABLE 0x50
#define CTX_INT_MASK_ENABLE_REG (CTX_LRM_INT_MASK_ENABLE + 1)
#define CTX_INT_MASK_ENABLE_PTR (CTX_LRM_INT_MASK_ENABLE + 2)
#define CTX_LRI_INT_REPORT_PTR 0x55
#define CTX_INT_STATUS_REPORT_REG (CTX_LRI_INT_REPORT_PTR + 1)
#define CTX_INT_STATUS_REPORT_PTR (CTX_LRI_INT_REPORT_PTR + 2)
#define CTX_INT_SRC_REPORT_REG (CTX_LRI_INT_REPORT_PTR + 3)
#define CTX_INT_SRC_REPORT_PTR (CTX_LRI_INT_REPORT_PTR + 4)
#define CTX_CS_INT_VEC_REG 0x5a
#define CTX_CS_INT_VEC_DATA (CTX_CS_INT_VEC_REG + 1)
#define CTX_QUEUE_TIMESTAMP (0xd0 + 1)
#define CTX_QUEUE_TIMESTAMP_UDW (0xd2 + 1)
#define INDIRECT_CTX_RING_HEAD (0x02 + 1)
#define INDIRECT_CTX_RING_TAIL (0x04 + 1)
#define INDIRECT_CTX_RING_START (0x06 + 1)
#define INDIRECT_CTX_RING_START_UDW (0x08 + 1)
#define INDIRECT_CTX_RING_CTL (0x0a + 1)
#endif
@@ -0,0 +1,48 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_MCHBAR_REGS_H_
#define _XE_MCHBAR_REGS_H_
#include "regs/xe_reg_defs.h"
/*
* MCHBAR mirror.
*
* This mirrors the MCHBAR MMIO space whose location is determined by
* device 0 function 0's pci config register 0x44 or 0x48 and matches it in
* every way.
*/
#define MCHBAR_MIRROR_BASE_SNB 0x140000
#define PCU_CR_PACKAGE_POWER_SKU XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x5930)
#define PKG_TDP GENMASK_ULL(14, 0)
#define PKG_MIN_PWR GENMASK_ULL(30, 16)
#define PKG_MAX_PWR GENMASK_ULL(46, 32)
#define PKG_MAX_WIN GENMASK_ULL(54, 48)
#define PKG_MAX_WIN_X GENMASK_ULL(54, 53)
#define PKG_MAX_WIN_Y GENMASK_ULL(52, 48)
#define PCU_CR_PACKAGE_POWER_SKU_UNIT XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x5938)
#define PKG_PWR_UNIT REG_GENMASK(3, 0)
#define PKG_ENERGY_UNIT REG_GENMASK(12, 8)
#define PKG_TIME_UNIT REG_GENMASK(19, 16)
#define PCU_CR_PACKAGE_ENERGY_STATUS XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x593c)
#define PCU_CR_PACKAGE_TEMPERATURE XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x5978)
#define TEMP_MASK REG_GENMASK(7, 0)
#define PCU_CR_PACKAGE_RAPL_LIMIT XE_REG(MCHBAR_MIRROR_BASE_SNB + 0x59a0)
#define PWR_LIM_VAL REG_GENMASK(14, 0)
#define PWR_LIM_EN REG_BIT(15)
#define PWR_LIM REG_GENMASK(15, 0)
#define PWR_LIM_TIME REG_GENMASK(23, 17)
#define PWR_LIM_TIME_X REG_GENMASK(23, 22)
#define PWR_LIM_TIME_Y REG_GENMASK(21, 17)
#endif /* _XE_MCHBAR_REGS_H_ */
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2025 Intel Corporation
*/
#ifndef _XE_MERT_REGS_H_
#define _XE_MERT_REGS_H_
#include "regs/xe_reg_defs.h"
#define MERT_LMEM_CFG XE_REG(0x1448b0)
#define MERT_TLB_CT_INTR_ERR_ID_PORT XE_REG(0x145190)
#define CATERR_VFID REG_GENMASK(16, 9)
#define CATERR_CODES REG_GENMASK(5, 0)
#define CATERR_NO_ERROR 0x00
#define CATERR_UNMAPPED_GGTT 0x01
#define CATERR_LMTT_FAULT 0x05
#define MERT_TLB_INV_DESC_A XE_REG(0x14cf7c)
#define MERT_TLB_INV_DESC_A_VALID REG_BIT(0)
#endif
@@ -0,0 +1,123 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef __XE_OA_REGS__
#define __XE_OA_REGS__
#define SYS_MEM_LAT_MEASURE XE_REG(0x145194)
#define SYS_MEM_LAT_MEASURE_EN REG_BIT(31)
#define RPM_CONFIG1 XE_REG(0xd04)
#define GT_NOA_ENABLE REG_BIT(9)
#define EU_PERF_CNTL0 XE_REG(0xe458)
#define EU_PERF_CNTL4 XE_REG(0xe45c)
#define EU_PERF_CNTL1 XE_REG(0xe558)
#define EU_PERF_CNTL5 XE_REG(0xe55c)
#define EU_PERF_CNTL2 XE_REG(0xe658)
#define EU_PERF_CNTL6 XE_REG(0xe65c)
#define EU_PERF_CNTL3 XE_REG(0xe758)
#define OA_TLB_INV_CR XE_REG(0xceec)
/* OAR unit */
#define OAR_OACONTROL XE_REG(0x2960)
#define OAR_OACONTROL_COUNTER_SEL_MASK REG_GENMASK(3, 1)
#define OAR_OACONTROL_COUNTER_ENABLE REG_BIT(0)
#define OACTXCONTROL(base) XE_REG((base) + 0x360)
#define OAR_OASTATUS XE_REG(0x2968)
#define OA_COUNTER_RESUME REG_BIT(0)
/* OAG unit */
#define OAG_OAGLBCTXCTRL XE_REG(0x2b28)
#define OAG_OAGLBCTXCTRL_TIMER_PERIOD_MASK REG_GENMASK(7, 2)
#define OAG_OAGLBCTXCTRL_TIMER_ENABLE REG_BIT(1)
#define OAG_OAGLBCTXCTRL_COUNTER_RESUME REG_BIT(0)
#define OAG_OAHEADPTR XE_REG(0xdb00)
#define OAG_OAHEADPTR_MASK REG_GENMASK(31, 6)
#define OAG_OATAILPTR XE_REG(0xdb04)
#define OAG_OATAILPTR_MASK REG_GENMASK(31, 6)
#define OAG_OABUFFER XE_REG(0xdb08)
#define OABUFFER_SIZE_MASK REG_GENMASK(5, 3)
#define OAG_OABUFFER_MEMORY_SELECT REG_BIT(0) /* 0: PPGTT, 1: GGTT */
#define OAG_OACONTROL XE_REG(0xdaf4)
#define OAG_OACONTROL_OA_PES_DISAG_EN REG_GENMASK(27, 22)
#define OAG_OACONTROL_OA_CCS_SELECT_MASK REG_GENMASK(18, 16)
#define OAG_OACONTROL_OA_COUNTER_SEL_MASK REG_GENMASK(4, 2)
#define OAG_OACONTROL_OA_COUNTER_ENABLE REG_BIT(0)
/* Common to all OA units */
#define OA_OACONTROL_REPORT_BC_MASK REG_GENMASK(9, 9)
#define OA_OACONTROL_COUNTER_SIZE_MASK REG_GENMASK(8, 8)
#define OAG_OACONTROL_USED_BITS \
(OAG_OACONTROL_OA_PES_DISAG_EN | OAG_OACONTROL_OA_CCS_SELECT_MASK | \
OAG_OACONTROL_OA_COUNTER_SEL_MASK | OAG_OACONTROL_OA_COUNTER_ENABLE | \
OA_OACONTROL_REPORT_BC_MASK | OA_OACONTROL_COUNTER_SIZE_MASK)
#define OAG_OA_DEBUG XE_REG(0xdaf8, XE_REG_OPTION_MASKED)
#define OAG_OA_DEBUG_DISABLE_MMIO_TRG REG_BIT(14)
#define OAG_OA_DEBUG_START_TRIGGER_SCOPE_CONTROL REG_BIT(13)
#define OAG_OA_DEBUG_BUF_SIZE_SELECT REG_BIT(12)
#define OAG_OA_DEBUG_DISABLE_START_TRG_2_COUNT_QUAL REG_BIT(8)
#define OAG_OA_DEBUG_DISABLE_START_TRG_1_COUNT_QUAL REG_BIT(7)
#define OAG_OA_DEBUG_INCLUDE_CLK_RATIO REG_BIT(6)
#define OAG_OA_DEBUG_DISABLE_CLK_RATIO_REPORTS REG_BIT(5)
#define OAG_OA_DEBUG_DISABLE_CTX_SWITCH_REPORTS REG_BIT(1)
#define OAG_OASTATUS XE_REG(0xdafc)
#define OASTATUS_MMIO_TRG_Q_FULL REG_BIT(6)
#define OASTATUS_COUNTER_OVERFLOW REG_BIT(2)
#define OASTATUS_BUFFER_OVERFLOW REG_BIT(1)
#define OASTATUS_REPORT_LOST REG_BIT(0)
#define OAG_MMIOTRIGGER XE_REG(0xdb1c)
/* OAC unit */
#define OAC_OACONTROL XE_REG(0x15114)
/* OAM unit */
#define OAM_HEAD_POINTER_OFFSET (0x1a0)
#define OAM_TAIL_POINTER_OFFSET (0x1a4)
#define OAM_BUFFER_OFFSET (0x1a8)
#define OAM_CONTEXT_CONTROL_OFFSET (0x1bc)
#define OAM_CONTROL_OFFSET (0x194)
#define OAM_CONTROL_COUNTER_SEL_MASK REG_GENMASK(3, 1)
#define OAM_OACONTROL_USED_BITS \
(OAM_CONTROL_COUNTER_SEL_MASK | OAG_OACONTROL_OA_COUNTER_ENABLE)
#define OAM_DEBUG_OFFSET (0x198)
#define OAM_STATUS_OFFSET (0x19c)
#define OAM_MMIO_TRG_OFFSET (0x1d0)
#define OAM_HEAD_POINTER(base) XE_REG((base) + OAM_HEAD_POINTER_OFFSET)
#define OAM_TAIL_POINTER(base) XE_REG((base) + OAM_TAIL_POINTER_OFFSET)
#define OAM_BUFFER(base) XE_REG((base) + OAM_BUFFER_OFFSET)
#define OAM_CONTEXT_CONTROL(base) XE_REG((base) + OAM_CONTEXT_CONTROL_OFFSET)
#define OAM_CONTROL(base) XE_REG((base) + OAM_CONTROL_OFFSET)
#define OAM_DEBUG(base) XE_REG((base) + OAM_DEBUG_OFFSET)
#define OAM_STATUS(base) XE_REG((base) + OAM_STATUS_OFFSET)
#define OAM_MMIO_TRG(base) XE_REG((base) + OAM_MMIO_TRG_OFFSET)
#define OAM_COMPRESSION_T3_CONTROL XE_REG(0x1c2e00)
#define OAM_LAT_MEASURE_ENABLE REG_BIT(4)
/* Actual address is MEDIA_GT_GSI_OFFSET + the base addr below */
#define XE_OAM_SAG_BASE 0x13000
#define XE_OAM_SCMI_0_BASE 0x14000
#define XE_OAM_SCMI_1_BASE 0x14800
#define XE_OAM_SAG_BASE_ADJ (MEDIA_GT_GSI_OFFSET + XE_OAM_SAG_BASE)
#define XE_OAM_SCMI_0_BASE_ADJ (MEDIA_GT_GSI_OFFSET + XE_OAM_SCMI_0_BASE)
#define XE_OAM_SCMI_1_BASE_ADJ (MEDIA_GT_GSI_OFFSET + XE_OAM_SCMI_1_BASE)
#define OAMERT_CONTROL XE_REG(0x1453a0)
#define OAMERT_DEBUG XE_REG(0x1453a4)
#define OAMERT_STATUS XE_REG(0x1453a8)
#define OAMERT_HEAD_POINTER XE_REG(0x1453ac)
#define OAMERT_TAIL_POINTER XE_REG(0x1453b0)
#define OAMERT_BUFFER XE_REG(0x1453b4)
#define OAMERT_CONTEXT_CONTROL XE_REG(0x1453c8)
#define OAMERT_MMIO_TRG XE_REG(0x1453cc)
#endif
@@ -0,0 +1,33 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef _XE_PCODE_REGS_H_
#define _XE_PCODE_REGS_H_
#include "regs/xe_reg_defs.h"
/*
* This file contains addresses of PCODE registers visible through GT MMIO space.
*/
#define PVC_GT0_PACKAGE_ENERGY_STATUS XE_REG(0x281004)
#define PVC_GT0_PACKAGE_RAPL_LIMIT XE_REG(0x281008)
#define PVC_GT0_PACKAGE_POWER_SKU_UNIT XE_REG(0x281068)
#define PVC_GT0_PLATFORM_ENERGY_STATUS XE_REG(0x28106c)
#define PVC_GT0_PACKAGE_POWER_SKU XE_REG(0x281080)
#define BMG_FAN_1_SPEED XE_REG(0x138140)
#define BMG_FAN_2_SPEED XE_REG(0x138170)
#define BMG_FAN_3_SPEED XE_REG(0x1381a0)
#define BMG_VRAM_TEMPERATURE_N(n) XE_REG(0x138260 + ((n) * (sizeof(u32))))
#define BMG_VRAM_TEMPERATURE XE_REG(0x1382c0)
#define TEMP_MASK_VRAM_N REG_GENMASK(30, 8)
#define TEMP_SIGN_MASK REG_BIT(31)
#define BMG_PACKAGE_TEMPERATURE XE_REG(0x138434)
#define CRI_PACKAGE_ENERGY_STATUS XE_REG(0x138120)
#define CRI_PLATFORM_ENERGY_STATUS XE_REG(0x138458)
#endif /* _XE_PCODE_REGS_H_ */
@@ -0,0 +1,32 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2024 Intel Corporation
*/
#ifndef _XE_PMT_H_
#define _XE_PMT_H_
#include "xe_regs.h"
#define BMG_PMT_BASE_OFFSET 0xDB000
#define BMG_DISCOVERY_OFFSET (SOC_BASE + BMG_PMT_BASE_OFFSET)
#define PUNIT_TELEMETRY_GUID XE_REG(BMG_DISCOVERY_OFFSET + 0x4)
#define BMG_ENERGY_STATUS_PMT_OFFSET (0x30)
#define ENERGY_PKG REG_GENMASK64(31, 0)
#define ENERGY_CARD REG_GENMASK64(63, 32)
#define BMG_TELEMETRY_BASE_OFFSET 0xE0000
#define BMG_TELEMETRY_OFFSET (SOC_BASE + BMG_TELEMETRY_BASE_OFFSET)
#define BMG_MODS_RESIDENCY_OFFSET (0x4D0)
#define BMG_G2_RESIDENCY_OFFSET (0x530)
#define BMG_G6_RESIDENCY_OFFSET (0x538)
#define BMG_G7_RESIDENCY_OFFSET (0x4B0)
#define BMG_G8_RESIDENCY_OFFSET (0x540)
#define BMG_G10_RESIDENCY_OFFSET (0x548)
#define BMG_PCIE_LINK_L0_RESIDENCY_OFFSET (0x570)
#define BMG_PCIE_LINK_L1_RESIDENCY_OFFSET (0x578)
#define BMG_PCIE_LINK_L1_2_RESIDENCY_OFFSET (0x580)
#endif
@@ -0,0 +1,23 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright(c) 2024, Intel Corporation. All rights reserved.
*/
#ifndef __XE_PXP_REGS_H__
#define __XE_PXP_REGS_H__
#include "regs/xe_regs.h"
/* The following registers are only valid on platforms with a media GT */
/* KCR enable/disable control */
#define KCR_INIT XE_REG(0x3860f0)
#define KCR_INIT_ALLOW_DISPLAY_ME_WRITES REG_BIT(14)
/* KCR hwdrm session in play status 0-31 */
#define KCR_SIP XE_REG(0x386260)
/* PXP global terminate register for session termination */
#define KCR_GLOBAL_TERMINATE XE_REG(0x3860f8)
#endif /* __XE_PXP_REGS_H__ */
@@ -0,0 +1,138 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_REG_DEFS_H_
#define _XE_REG_DEFS_H_
#include <drm/intel/pick.h>
#include <drm/intel/reg_bits.h>
#include <linux/build_bug.h>
#include <linux/log2.h>
#include <linux/sizes.h>
/**
* XE_REG_ADDR_MAX - The upper limit on MMIO register address
*
* This macro specifies the upper limit (not inclusive) on MMIO register offset
* supported by struct xe_reg and functions based on struct xe_mmio.
*
* Currently this is defined as 4 MiB.
*/
#define XE_REG_ADDR_MAX SZ_4M
/**
* struct xe_reg - Register definition
*
* Register definition to be used by the individual register. Although the same
* definition is used for xe_reg and xe_reg_mcr, they use different internal
* APIs for accesses.
*/
struct xe_reg {
union {
struct {
/** @addr: address */
u32 addr:const_ilog2(XE_REG_ADDR_MAX);
/**
* @masked: register is "masked", with upper 16bits used
* to identify the bits that are updated on the lower
* bits
*/
u32 masked:1;
/**
* @mcr: register is multicast/replicated in the
* hardware and needs special handling. Any register
* with this set should also use a type of xe_reg_mcr_t.
* It's only here so the few places that deal with MCR
* registers specially (xe_sr.c) and tests using the raw
* value can inspect it.
*/
u32 mcr:1;
/**
* @vf: register is accessible from the Virtual Function.
*/
u32 vf:1;
};
/** @raw: Raw value with both address and options */
u32 raw;
};
};
static_assert(sizeof(struct xe_reg) == sizeof(u32));
/**
* struct xe_reg_mcr - MCR register definition
*
* MCR register is the same as a regular register, but uses another type since
* the internal API used for accessing them is different: it's never correct to
* use regular MMIO access.
*/
struct xe_reg_mcr {
/** @__reg: The register */
struct xe_reg __reg;
};
/**
* XE_REG_OPTION_MASKED - Register is "masked", with upper 16 bits marking the
* written bits on the lower 16 bits.
*
* It only applies to registers explicitly marked in bspec with
* "Access: Masked". Registers with this option can have write operations to
* specific lower bits by setting the corresponding upper bits. Other bits will
* not be affected. This allows register writes without needing a RMW cycle and
* without caching in software the register value.
*
* Example: a write with value 0x00010001 will set bit 0 and all other bits
* retain their previous values.
*
* To be used with XE_REG(). XE_REG_MCR() and XE_REG_INITIALIZER()
*/
#define XE_REG_OPTION_MASKED .masked = 1
/**
* XE_REG_OPTION_VF - Register is "VF" accessible.
*
* To be used with XE_REG() and XE_REG_INITIALIZER().
*/
#define XE_REG_OPTION_VF .vf = 1
/**
* XE_REG_INITIALIZER - Initializer for xe_reg_t.
* @r_: Register offset
* @...: Additional options like access mode. See struct xe_reg for available
* options.
*
* Register field is mandatory, and additional options may be passed as
* arguments. Usually ``XE_REG()`` should be preferred since it creates an
* object of the right type. However when initializing static const storage,
* where a compound statement is not allowed, this can be used instead.
*/
#define XE_REG_INITIALIZER(r_, ...) { .addr = r_, __VA_ARGS__ }
/**
* XE_REG - Create a struct xe_reg from offset and additional flags
* @r_: Register offset
* @...: Additional options like access mode. See struct xe_reg for available
* options.
*/
#define XE_REG(r_, ...) ((const struct xe_reg)XE_REG_INITIALIZER(r_, ##__VA_ARGS__))
/**
* XE_REG_MCR - Create a struct xe_reg_mcr from offset and additional flags
* @r_: Register offset
* @...: Additional options like access mode. See struct xe_reg for available
* options.
*/
#define XE_REG_MCR(r_, ...) ((const struct xe_reg_mcr){ \
.__reg = XE_REG_INITIALIZER(r_, ##__VA_ARGS__, .mcr = 1) \
})
static inline bool xe_reg_is_valid(struct xe_reg r)
{
return r.addr;
}
#endif
@@ -0,0 +1,65 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_REGS_H_
#define _XE_REGS_H_
#include "regs/xe_reg_defs.h"
#define SOC_BASE 0x280000
#define GU_CNTL_PROTECTED XE_REG(0x10100C)
#define DRIVERINT_FLR_DIS REG_BIT(31)
#define GU_CNTL XE_REG(0x101010)
#define LMEM_INIT REG_BIT(7)
#define DRIVERFLR REG_BIT(31)
#define XEHP_CLOCK_GATE_DIS XE_REG(0x101014)
#define SGSI_SIDECLK_DIS REG_BIT(17)
#define GU_DEBUG XE_REG(0x101018)
#define DRIVERFLR_STATUS REG_BIT(31)
#define VIRTUAL_CTRL_REG XE_REG(0x10108c)
#define GUEST_GTT_UPDATE_EN REG_BIT(8)
#define XEHP_MTCFG_ADDR XE_REG(0x101800)
#define TILE_COUNT REG_GENMASK(15, 8)
#define GGC XE_REG(0x108040)
#define GMS_MASK REG_GENMASK(15, 8)
#define GGMS_MASK REG_GENMASK(7, 6)
#define DSMBASE XE_REG(0x1080C0)
#define BDSM_MASK REG_GENMASK64(63, 20)
#define GSMBASE XE_REG(0x108100)
#define STOLEN_RESERVED XE_REG(0x1082c0)
#define WOPCM_SIZE_MASK REG_GENMASK64(9, 7)
#define SG_TILE_ADDR_RANGE(_idx) XE_REG(0x1083a0 + (_idx) * 4)
#define MTL_RP_STATE_CAP XE_REG(0x138000)
#define MTL_GT_RPA_FREQUENCY XE_REG(0x138008)
#define MTL_GT_RPE_FREQUENCY XE_REG(0x13800c)
#define MTL_MEDIAP_STATE_CAP XE_REG(0x138020)
#define MTL_RPN_CAP_MASK REG_GENMASK(24, 16)
#define MTL_RP0_CAP_MASK REG_GENMASK(8, 0)
#define MTL_MPA_FREQUENCY XE_REG(0x138028)
#define MTL_RPA_MASK REG_GENMASK(8, 0)
#define MTL_MPE_FREQUENCY XE_REG(0x13802c)
#define MTL_RPE_MASK REG_GENMASK(8, 0)
#define VF_CAP_REG XE_REG(0x1901f8, XE_REG_OPTION_VF)
#define VF_CAP REG_BIT(0)
#define PVC_RP_STATE_CAP XE_REG(0x281014)
#endif
@@ -0,0 +1,14 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2025 Intel Corporation
*/
#ifndef _XE_SOC_REMAPPER_REGS_H_
#define _XE_SOC_REMAPPER_REGS_H_
#include "xe_regs.h"
#define SG_REMAP_INDEX1 XE_REG(SOC_BASE + 0x08)
#define SG_REMAP_TELEM_MASK REG_GENMASK(31, 24)
#define SG_REMAP_SYSCTRL_MASK REG_GENMASK(23, 16)
#endif
@@ -0,0 +1,36 @@
/* SPDX-License-Identifier: MIT */
/*
* Copyright © 2026 Intel Corporation
*/
#ifndef _XE_SYSCTRL_REGS_H_
#define _XE_SYSCTRL_REGS_H_
#include "xe_regs.h"
#define SYSCTRL_BASE_OFFSET 0xdb000
#define SYSCTRL_BASE (SOC_BASE + SYSCTRL_BASE_OFFSET)
#define SYSCTRL_MAILBOX_INDEX 0x03
#define SYSCTRL_BAR_LENGTH 0x1000
#define SYSCTRL_MB_CTRL XE_REG(0x10)
#define SYSCTRL_MB_CTRL_RUN_BUSY REG_BIT(31)
#define SYSCTRL_MB_CTRL_IRQ REG_BIT(30)
#define SYSCTRL_MB_CTRL_RUN_BUSY_OUT REG_BIT(29)
#define SYSCTRL_MB_CTRL_PARAM3_MASK REG_GENMASK(28, 24)
#define SYSCTRL_MB_CTRL_PARAM2_MASK REG_GENMASK(23, 16)
#define SYSCTRL_MB_CTRL_PARAM1_MASK REG_GENMASK(15, 8)
#define SYSCTRL_MB_CTRL_COMMAND_MASK REG_GENMASK(7, 0)
#define SYSCTRL_MB_CTRL_CMD REG_FIELD_PREP(SYSCTRL_MB_CTRL_COMMAND_MASK, 5)
#define SYSCTRL_MB_DATA0 XE_REG(0x14)
#define SYSCTRL_MB_DATA1 XE_REG(0x18)
#define SYSCTRL_MB_DATA2 XE_REG(0x1c)
#define SYSCTRL_MB_DATA3 XE_REG(0x20)
#define SYSCTRL_FRAME_PHASE REG_BIT(24)
#define SYSCTRL_FRAME_CURRENT_MASK REG_GENMASK(21, 16)
#define SYSCTRL_FRAME_TOTAL_MASK REG_GENMASK(13, 8)
#define SYSCTRL_FRAME_COMMAND_MASK REG_GENMASK(7, 0)
#endif
@@ -0,0 +1,13 @@
# SPDX-License-Identifier: GPL-2.0
# "live" kunit tests
obj-$(CONFIG_DRM_XE_KUNIT_TEST) += xe_live_test.o
xe_live_test-y = xe_live_test_mod.o
# Normal kunit tests
obj-$(CONFIG_DRM_XE_KUNIT_TEST) += xe_test.o
xe_test-y = xe_test_mod.o \
xe_args_test.o \
xe_pci_test.o \
xe_rtp_test.o \
xe_wa_test.o
@@ -0,0 +1,275 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright © 2024 Intel Corporation
*/
#include <kunit/test.h>
#include "xe_args.h"
static void call_args_example(struct kunit *test)
{
#define foo X, Y, Z, Q
#define bar COUNT_ARGS(foo)
#define buz CALL_ARGS(COUNT_ARGS, foo)
KUNIT_EXPECT_EQ(test, bar, 1);
KUNIT_EXPECT_EQ(test, buz, 4);
#undef foo
#undef bar
#undef buz
}
static void drop_first_arg_example(struct kunit *test)
{
#define foo X, Y, Z, Q
#define bar CALL_ARGS(COUNT_ARGS, DROP_FIRST_ARG(foo))
KUNIT_EXPECT_EQ(test, bar, 3);
#undef foo
#undef bar
}
static void first_arg_example(struct kunit *test)
{
int X = 1;
#define foo X, Y, Z, Q
#define bar FIRST_ARG(foo)
KUNIT_EXPECT_EQ(test, bar, X);
KUNIT_EXPECT_STREQ(test, __stringify(bar), "X");
#undef foo
#undef bar
}
static void last_arg_example(struct kunit *test)
{
int Q = 1;
#define foo X, Y, Z, Q
#define bar LAST_ARG(foo)
KUNIT_EXPECT_EQ(test, bar, Q);
KUNIT_EXPECT_STREQ(test, __stringify(bar), "Q");
#undef foo
#undef bar
}
static void pick_arg_example(struct kunit *test)
{
int Y = 1, Z = 2;
#define foo X, Y, Z, Q
#define bar PICK_ARG(2, foo)
#define buz PICK_ARG3(foo)
KUNIT_EXPECT_EQ(test, bar, Y);
KUNIT_EXPECT_STREQ(test, __stringify(bar), "Y");
KUNIT_EXPECT_EQ(test, buz, Z);
KUNIT_EXPECT_STREQ(test, __stringify(buz), "Z");
#undef foo
#undef bar
#undef buz
}
static void if_args_example(struct kunit *test)
{
enum { Z = 1, Q };
#define foo X, Y
#define bar IF_ARGS(Z, Q, foo)
#define buz IF_ARGS(Z, Q, DROP_FIRST_ARG(FIRST_ARG(foo)))
KUNIT_EXPECT_EQ(test, bar, Z);
KUNIT_EXPECT_EQ(test, buz, Q);
KUNIT_EXPECT_STREQ(test, __stringify(bar), "Z");
KUNIT_EXPECT_STREQ(test, __stringify(buz), "Q");
#undef foo
#undef bar
#undef buz
}
static void sep_comma_example(struct kunit *test)
{
#define foo(f) f(X) f(Y) f(Z) f(Q)
#define bar DROP_FIRST_ARG(foo(ARGS_SEP_COMMA __stringify))
#define buz CALL_ARGS(COUNT_ARGS, DROP_FIRST_ARG(foo(ARGS_SEP_COMMA)))
static const char * const a[] = { bar };
KUNIT_EXPECT_STREQ(test, a[0], "X");
KUNIT_EXPECT_STREQ(test, a[1], "Y");
KUNIT_EXPECT_STREQ(test, a[2], "Z");
KUNIT_EXPECT_STREQ(test, a[3], "Q");
KUNIT_EXPECT_EQ(test, buz, 4);
#undef foo
#undef bar
#undef buz
}
#define NO_ARGS
#define FOO_ARGS X, Y, Z, Q
#define MAX_ARGS -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12
static void count_args_test(struct kunit *test)
{
int count;
/* COUNT_ARGS() counts to 12 */
count = COUNT_ARGS();
KUNIT_EXPECT_EQ(test, count, 0);
count = COUNT_ARGS(1);
KUNIT_EXPECT_EQ(test, count, 1);
count = COUNT_ARGS(a, b, c, d, e);
KUNIT_EXPECT_EQ(test, count, 5);
count = COUNT_ARGS(a, b, c, d, e, f, g, h, i, j, k, l);
KUNIT_EXPECT_EQ(test, count, 12);
/* COUNT_ARGS() does not expand params */
count = COUNT_ARGS(NO_ARGS);
KUNIT_EXPECT_EQ(test, count, 1);
count = COUNT_ARGS(FOO_ARGS);
KUNIT_EXPECT_EQ(test, count, 1);
}
static void call_args_test(struct kunit *test)
{
int count;
count = CALL_ARGS(COUNT_ARGS, NO_ARGS);
KUNIT_EXPECT_EQ(test, count, 0);
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, NO_ARGS), 0);
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, FOO_ARGS), 4);
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, FOO_ARGS, FOO_ARGS), 8);
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, MAX_ARGS), 12);
}
static void drop_first_arg_test(struct kunit *test)
{
int Y = -2, Z = -3, Q = -4;
int a[] = { DROP_FIRST_ARG(FOO_ARGS) };
KUNIT_EXPECT_EQ(test, DROP_FIRST_ARG(0, -1), -1);
KUNIT_EXPECT_EQ(test, DROP_FIRST_ARG(DROP_FIRST_ARG(0, -1, -2)), -2);
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, DROP_FIRST_ARG(FOO_ARGS)), 3);
KUNIT_EXPECT_EQ(test, DROP_FIRST_ARG(DROP_FIRST_ARG(DROP_FIRST_ARG(FOO_ARGS))), -4);
KUNIT_EXPECT_EQ(test, a[0], -2);
KUNIT_EXPECT_EQ(test, a[1], -3);
KUNIT_EXPECT_EQ(test, a[2], -4);
#define foo DROP_FIRST_ARG(FOO_ARGS)
#define bar DROP_FIRST_ARG(DROP_FIRST_ARG(FOO_ARGS))
#define buz DROP_FIRST_ARG(DROP_FIRST_ARG(DROP_FIRST_ARG(FOO_ARGS)))
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, foo), 3);
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, bar), 2);
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, buz), 1);
KUNIT_EXPECT_STREQ(test, __stringify(buz), "Q");
#undef foo
#undef bar
#undef buz
}
static void first_arg_test(struct kunit *test)
{
int X = -1;
int a[] = { FIRST_ARG(FOO_ARGS) };
KUNIT_EXPECT_EQ(test, FIRST_ARG(-1, -2), -1);
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, FIRST_ARG(FOO_ARGS)), 1);
KUNIT_EXPECT_EQ(test, FIRST_ARG(FOO_ARGS), -1);
KUNIT_EXPECT_EQ(test, a[0], -1);
KUNIT_EXPECT_STREQ(test, __stringify(FIRST_ARG(FOO_ARGS)), "X");
}
static void last_arg_test(struct kunit *test)
{
int Q = -4;
int a[] = { LAST_ARG(FOO_ARGS) };
KUNIT_EXPECT_EQ(test, LAST_ARG(-1, -2), -2);
KUNIT_EXPECT_EQ(test, CALL_ARGS(COUNT_ARGS, LAST_ARG(FOO_ARGS)), 1);
KUNIT_EXPECT_EQ(test, LAST_ARG(FOO_ARGS), -4);
KUNIT_EXPECT_EQ(test, a[0], -4);
KUNIT_EXPECT_STREQ(test, __stringify(LAST_ARG(FOO_ARGS)), "Q");
KUNIT_EXPECT_EQ(test, LAST_ARG(MAX_ARGS), -12);
KUNIT_EXPECT_STREQ(test, __stringify(LAST_ARG(MAX_ARGS)), "-12");
}
static void if_args_test(struct kunit *test)
{
bool with_args = true;
bool no_args = false;
enum { X = 100 };
KUNIT_EXPECT_TRUE(test, IF_ARGS(true, false, FOO_ARGS));
KUNIT_EXPECT_FALSE(test, IF_ARGS(true, false, NO_ARGS));
KUNIT_EXPECT_TRUE(test, CONCATENATE(IF_ARGS(with, no, FOO_ARGS), _args));
KUNIT_EXPECT_FALSE(test, CONCATENATE(IF_ARGS(with, no, NO_ARGS), _args));
KUNIT_EXPECT_STREQ(test, __stringify(IF_ARGS(yes, no, FOO_ARGS)), "yes");
KUNIT_EXPECT_STREQ(test, __stringify(IF_ARGS(yes, no, NO_ARGS)), "no");
KUNIT_EXPECT_EQ(test, IF_ARGS(CALL_ARGS(COUNT_ARGS, FOO_ARGS), -1, FOO_ARGS), 4);
KUNIT_EXPECT_EQ(test, IF_ARGS(CALL_ARGS(COUNT_ARGS, FOO_ARGS), -1, NO_ARGS), -1);
KUNIT_EXPECT_EQ(test, IF_ARGS(CALL_ARGS(COUNT_ARGS, NO_ARGS), -1, FOO_ARGS), 0);
KUNIT_EXPECT_EQ(test, IF_ARGS(CALL_ARGS(COUNT_ARGS, NO_ARGS), -1, NO_ARGS), -1);
KUNIT_EXPECT_EQ(test,
CALL_ARGS(FIRST_ARG,
CALL_ARGS(CONCATENATE, IF_ARGS(FOO, MAX, FOO_ARGS), _ARGS)), X);
KUNIT_EXPECT_EQ(test,
CALL_ARGS(FIRST_ARG,
CALL_ARGS(CONCATENATE, IF_ARGS(FOO, MAX, NO_ARGS), _ARGS)), -1);
KUNIT_EXPECT_EQ(test,
CALL_ARGS(COUNT_ARGS,
CALL_ARGS(CONCATENATE, IF_ARGS(FOO, MAX, FOO_ARGS), _ARGS)), 4);
KUNIT_EXPECT_EQ(test,
CALL_ARGS(COUNT_ARGS,
CALL_ARGS(CONCATENATE, IF_ARGS(FOO, MAX, NO_ARGS), _ARGS)), 12);
}
static struct kunit_case args_tests[] = {
KUNIT_CASE(count_args_test),
KUNIT_CASE(call_args_example),
KUNIT_CASE(call_args_test),
KUNIT_CASE(drop_first_arg_example),
KUNIT_CASE(drop_first_arg_test),
KUNIT_CASE(first_arg_example),
KUNIT_CASE(first_arg_test),
KUNIT_CASE(last_arg_example),
KUNIT_CASE(last_arg_test),
KUNIT_CASE(pick_arg_example),
KUNIT_CASE(if_args_example),
KUNIT_CASE(if_args_test),
KUNIT_CASE(sep_comma_example),
{}
};
static struct kunit_suite args_test_suite = {
.name = "args",
.test_cases = args_tests,
};
kunit_test_suite(args_test_suite);
@@ -0,0 +1,632 @@
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2022 Intel Corporation
*/
#include <kunit/test.h>
#include <kunit/visibility.h>
#include <linux/iosys-map.h>
#include <linux/math64.h>
#include <linux/prandom.h>
#include <linux/swap.h>
#include <uapi/linux/sysinfo.h>
#include "tests/xe_kunit_helpers.h"
#include "tests/xe_pci_test.h"
#include "tests/xe_test.h"
#include "xe_bo_evict.h"
#include "xe_gt.h"
#include "xe_pci.h"
#include "xe_pm.h"
static int ccs_test_migrate(struct xe_tile *tile, struct xe_bo *bo,
bool clear, u64 get_val, u64 assign_val,
struct kunit *test, struct drm_exec *exec)
{
struct dma_fence *fence;
struct ttm_tt *ttm;
struct page *page;
pgoff_t ccs_page;
long timeout;
u64 *cpu_map;
int ret;
u32 offset;
/* Move bo to VRAM if not already there. */
ret = xe_bo_validate(bo, NULL, false, exec);
if (ret) {
KUNIT_FAIL(test, "Failed to validate bo.\n");
return ret;
}
/* Optionally clear bo *and* CCS data in VRAM. */
if (clear) {
fence = xe_migrate_clear(tile->migrate, bo, bo->ttm.resource,
XE_MIGRATE_CLEAR_FLAG_FULL);
if (IS_ERR(fence)) {
KUNIT_FAIL(test, "Failed to submit bo clear.\n");
return PTR_ERR(fence);
}
if (dma_fence_wait_timeout(fence, false, 5 * HZ) <= 0) {
dma_fence_put(fence);
KUNIT_FAIL(test, "Timeout while clearing bo.\n");
return -ETIME;
}
dma_fence_put(fence);
}
/* Evict to system. CCS data should be copied. */
ret = xe_bo_evict(bo, exec);
if (ret) {
KUNIT_FAIL(test, "Failed to evict bo.\n");
return ret;
}
/* Sync all migration blits */
timeout = dma_resv_wait_timeout(bo->ttm.base.resv,
DMA_RESV_USAGE_KERNEL,
true,
5 * HZ);
if (timeout <= 0) {
KUNIT_FAIL(test, "Failed to sync bo eviction.\n");
return -ETIME;
}
/*
* Bo with CCS data is now in system memory. Verify backing store
* and data integrity. Then assign for the next testing round while
* we still have a CPU map.
*/
ttm = bo->ttm.ttm;
if (!ttm || !ttm_tt_is_populated(ttm)) {
KUNIT_FAIL(test, "Bo was not in expected placement.\n");
return -EINVAL;
}
ccs_page = xe_bo_ccs_pages_start(bo) >> PAGE_SHIFT;
if (ccs_page >= ttm->num_pages) {
KUNIT_FAIL(test, "No TTM CCS pages present.\n");
return -EINVAL;
}
page = ttm->pages[ccs_page];
cpu_map = kmap_local_page(page);
/* Check first CCS value */
if (cpu_map[0] != get_val) {
KUNIT_FAIL(test,
"Expected CCS readout 0x%016llx, got 0x%016llx.\n",
(unsigned long long)get_val,
(unsigned long long)cpu_map[0]);
ret = -EINVAL;
}
/* Check last CCS value, or at least last value in page. */
offset = xe_device_ccs_bytes(tile_to_xe(tile), xe_bo_size(bo));
offset = min_t(u32, offset, PAGE_SIZE) / sizeof(u64) - 1;
if (cpu_map[offset] != get_val) {
KUNIT_FAIL(test,
"Expected CCS readout 0x%016llx, got 0x%016llx.\n",
(unsigned long long)get_val,
(unsigned long long)cpu_map[offset]);
ret = -EINVAL;
}
cpu_map[0] = assign_val;
cpu_map[offset] = assign_val;
kunmap_local(cpu_map);
return ret;
}
static void ccs_test_run_tile(struct xe_device *xe, struct xe_tile *tile,
struct kunit *test)
{
struct xe_bo *bo;
int ret;
/* TODO: Sanity check */
unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
if (IS_DGFX(xe))
kunit_info(test, "Testing vram id %u\n", tile->id);
else
kunit_info(test, "Testing system memory\n");
bo = xe_bo_create_user(xe, NULL, SZ_1M, DRM_XE_GEM_CPU_CACHING_WC,
bo_flags, exec);
if (IS_ERR(bo)) {
KUNIT_FAIL(test, "Failed to create bo.\n");
return;
}
xe_bo_lock(bo, false);
kunit_info(test, "Verifying that CCS data is cleared on creation.\n");
ret = ccs_test_migrate(tile, bo, false, 0ULL, 0xdeadbeefdeadbeefULL,
test, exec);
if (ret)
goto out_unlock;
kunit_info(test, "Verifying that CCS data survives migration.\n");
ret = ccs_test_migrate(tile, bo, false, 0xdeadbeefdeadbeefULL,
0xdeadbeefdeadbeefULL, test, exec);
if (ret)
goto out_unlock;
kunit_info(test, "Verifying that CCS data can be properly cleared.\n");
ret = ccs_test_migrate(tile, bo, true, 0ULL, 0ULL, test, exec);
out_unlock:
xe_bo_unlock(bo);
xe_bo_put(bo);
}
static int ccs_test_run_device(struct xe_device *xe)
{
struct kunit *test = kunit_get_current_test();
struct xe_tile *tile;
int id;
if (!xe_device_has_flat_ccs(xe)) {
kunit_skip(test, "non-flat-ccs device\n");
return 0;
}
/* For xe2+ dgfx, we don't handle ccs metadata */
if (GRAPHICS_VER(xe) >= 20 && IS_DGFX(xe)) {
kunit_skip(test, "xe2+ dgfx device\n");
return 0;
}
guard(xe_pm_runtime)(xe);
for_each_tile(tile, xe, id) {
/* For igfx run only for primary tile */
if (!IS_DGFX(xe) && id > 0)
continue;
ccs_test_run_tile(xe, tile, test);
}
return 0;
}
static void xe_ccs_migrate_kunit(struct kunit *test)
{
struct xe_device *xe = test->priv;
ccs_test_run_device(xe);
}
static int evict_test_run_tile(struct xe_device *xe, struct xe_tile *tile, struct kunit *test)
{
struct xe_bo *bo, *external;
unsigned int bo_flags = XE_BO_FLAG_VRAM_IF_DGFX(tile);
struct xe_vm *vm = xe_migrate_get_vm(xe_device_get_root_tile(xe)->migrate);
struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
struct xe_gt *__gt;
int err, i, id;
kunit_info(test, "Testing device %s vram id %u\n",
dev_name(xe->drm.dev), tile->id);
for (i = 0; i < 2; ++i) {
xe_vm_lock(vm, false);
bo = xe_bo_create_user(xe, vm, 0x10000,
DRM_XE_GEM_CPU_CACHING_WC,
bo_flags, exec);
xe_vm_unlock(vm);
if (IS_ERR(bo)) {
KUNIT_FAIL(test, "bo create err=%pe\n", bo);
break;
}
external = xe_bo_create_user(xe, NULL, 0x10000,
DRM_XE_GEM_CPU_CACHING_WC,
bo_flags, NULL);
if (IS_ERR(external)) {
KUNIT_FAIL(test, "external bo create err=%pe\n", external);
goto cleanup_bo;
}
xe_bo_lock(external, false);
err = xe_bo_pin_external(external, false, exec);
xe_bo_unlock(external);
if (err) {
KUNIT_FAIL(test, "external bo pin err=%pe\n",
ERR_PTR(err));
goto cleanup_external;
}
err = xe_bo_evict_all(xe);
if (err) {
KUNIT_FAIL(test, "evict err=%pe\n", ERR_PTR(err));
goto cleanup_all;
}
for_each_gt(__gt, xe, id)
xe_gt_sanitize(__gt);
err = xe_bo_restore_early(xe);
/*
* Snapshotting the CTB and copying back a potentially old
* version seems risky, depending on what might have been
* inflight. Also it seems snapshotting the ADS object and
* copying back results in serious breakage. Normally when
* calling xe_bo_restore_kernel() we always fully restart the
* GT, which re-intializes such things. We could potentially
* skip saving and restoring such objects in xe_bo_evict_all()
* however seems quite fragile not to also restart the GT. Try
* to do that here by triggering a GT reset.
*/
for_each_gt(__gt, xe, id)
xe_gt_reset(__gt);
if (err) {
KUNIT_FAIL(test, "restore kernel err=%pe\n",
ERR_PTR(err));
goto cleanup_all;
}
err = xe_bo_restore_late(xe);
if (err) {
KUNIT_FAIL(test, "restore user err=%pe\n", ERR_PTR(err));
goto cleanup_all;
}
if (!xe_bo_is_vram(external)) {
KUNIT_FAIL(test, "external bo is not vram\n");
err = -EPROTO;
goto cleanup_all;
}
if (xe_bo_is_vram(bo)) {
KUNIT_FAIL(test, "bo is vram\n");
err = -EPROTO;
goto cleanup_all;
}
if (i) {
down_read(&vm->lock);
xe_vm_lock(vm, false);
err = xe_bo_validate(bo, bo->vm, false, exec);
xe_vm_unlock(vm);
up_read(&vm->lock);
if (err) {
KUNIT_FAIL(test, "bo valid err=%pe\n",
ERR_PTR(err));
goto cleanup_all;
}
xe_bo_lock(external, false);
err = xe_bo_validate(external, NULL, false, exec);
xe_bo_unlock(external);
if (err) {
KUNIT_FAIL(test, "external bo valid err=%pe\n",
ERR_PTR(err));
goto cleanup_all;
}
}
xe_bo_lock(external, false);
xe_bo_unpin_external(external);
xe_bo_unlock(external);
xe_bo_put(external);
xe_bo_lock(bo, false);
__xe_bo_unset_bulk_move(bo);
xe_bo_unlock(bo);
xe_bo_put(bo);
continue;
cleanup_all:
xe_bo_lock(external, false);
xe_bo_unpin_external(external);
xe_bo_unlock(external);
cleanup_external:
xe_bo_put(external);
cleanup_bo:
xe_bo_lock(bo, false);
__xe_bo_unset_bulk_move(bo);
xe_bo_unlock(bo);
xe_bo_put(bo);
break;
}
xe_vm_put(vm);
return 0;
}
static int evict_test_run_device(struct xe_device *xe)
{
struct kunit *test = kunit_get_current_test();
struct xe_tile *tile;
int id;
if (!IS_DGFX(xe)) {
kunit_skip(test, "non-discrete device\n");
return 0;
}
guard(xe_pm_runtime)(xe);
for_each_tile(tile, xe, id)
evict_test_run_tile(xe, tile, test);
return 0;
}
static void xe_bo_evict_kunit(struct kunit *test)
{
struct xe_device *xe = test->priv;
evict_test_run_device(xe);
}
struct xe_bo_link {
struct list_head link;
struct xe_bo *bo;
u32 val;
};
#define XE_BO_SHRINK_SIZE ((unsigned long)SZ_64M)
static int shrink_test_fill_random(struct xe_bo *bo, struct rnd_state *state,
struct xe_bo_link *link)
{
struct iosys_map map;
int ret = ttm_bo_vmap(&bo->ttm, &map);
size_t __maybe_unused i;
if (ret)
return ret;
for (i = 0; i < bo->ttm.base.size; i += sizeof(u32)) {
u32 val = prandom_u32_state(state);
iosys_map_wr(&map, i, u32, val);
if (i == 0)
link->val = val;
}
ttm_bo_vunmap(&bo->ttm, &map);
return 0;
}
static bool shrink_test_verify(struct kunit *test, struct xe_bo *bo,
unsigned int bo_nr, struct rnd_state *state,
struct xe_bo_link *link)
{
struct iosys_map map;
int ret = ttm_bo_vmap(&bo->ttm, &map);
size_t i;
bool failed = false;
if (ret) {
KUNIT_FAIL(test, "Error mapping bo %u for content check.\n", bo_nr);
return true;
}
for (i = 0; i < bo->ttm.base.size; i += sizeof(u32)) {
u32 val = prandom_u32_state(state);
if (iosys_map_rd(&map, i, u32) != val) {
KUNIT_FAIL(test, "Content not preserved, bo %u offset 0x%016llx",
bo_nr, (unsigned long long)i);
kunit_info(test, "Failed value is 0x%08x, recorded 0x%08x\n",
(unsigned int)iosys_map_rd(&map, i, u32), val);
if (i == 0 && val != link->val)
kunit_info(test, "Looks like PRNG is out of sync.\n");
failed = true;
break;
}
}
ttm_bo_vunmap(&bo->ttm, &map);
return failed;
}
/*
* Try to create system bos corresponding to twice the amount
* of available system memory to test shrinker functionality.
* If no swap space is available to accommodate the
* memory overcommit, mark bos purgeable.
*/
static int shrink_test_run_device(struct xe_device *xe)
{
struct kunit *test = kunit_get_current_test();
LIST_HEAD(bos);
struct xe_bo_link *link, *next;
struct sysinfo si;
u64 ram, ram_and_swap, purgeable = 0, alloced, to_alloc, limit;
unsigned int interrupted = 0, successful = 0, count = 0;
struct rnd_state prng;
u64 rand_seed;
bool failed = false;
rand_seed = get_random_u64();
prandom_seed_state(&prng, rand_seed);
kunit_info(test, "Random seed is 0x%016llx.\n",
(unsigned long long)rand_seed);
/* Skip if execution time is expected to be too long. */
limit = SZ_32G;
/* IGFX with flat CCS needs to copy when swapping / shrinking */
if (!IS_DGFX(xe) && xe_device_has_flat_ccs(xe))
limit = SZ_16G;
si_meminfo(&si);
ram = (size_t)si.freeram * si.mem_unit;
if (ram > limit) {
kunit_skip(test, "Too long expected execution time.\n");
return 0;
}
to_alloc = ram * 2;
ram_and_swap = ram + get_nr_swap_pages() * PAGE_SIZE;
if (to_alloc > ram_and_swap)
purgeable = to_alloc - ram_and_swap;
purgeable += div64_u64(purgeable, 5);
kunit_info(test, "Free ram is %lu bytes. Will allocate twice of that.\n",
(unsigned long)ram);
for (alloced = 0; alloced < to_alloc; alloced += XE_BO_SHRINK_SIZE) {
struct xe_bo *bo;
unsigned int mem_type;
struct xe_ttm_tt *xe_tt;
link = kzalloc_obj(*link);
if (!link) {
KUNIT_FAIL(test, "Unexpected link allocation failure\n");
failed = true;
break;
}
INIT_LIST_HEAD(&link->link);
/* We can create bos using WC caching here. But it is slower. */
bo = xe_bo_create_user(xe, NULL, XE_BO_SHRINK_SIZE,
DRM_XE_GEM_CPU_CACHING_WB,
XE_BO_FLAG_SYSTEM, NULL);
if (IS_ERR(bo)) {
if (bo != ERR_PTR(-ENOMEM) && bo != ERR_PTR(-ENOSPC) &&
bo != ERR_PTR(-EINTR) && bo != ERR_PTR(-ERESTARTSYS))
KUNIT_FAIL(test, "Error creating bo: %pe\n", bo);
kfree(link);
failed = true;
break;
}
xe_bo_lock(bo, false);
xe_tt = container_of(bo->ttm.ttm, typeof(*xe_tt), ttm);
/*
* Allocate purgeable bos first, because if we do it the
* other way around, they may not be subject to swapping...
*/
if (alloced < purgeable) {
xe_ttm_tt_account_subtract(xe, &xe_tt->ttm);
xe_tt->purgeable = true;
xe_ttm_tt_account_add(xe, &xe_tt->ttm);
bo->ttm.priority = 0;
spin_lock(&bo->ttm.bdev->lru_lock);
ttm_bo_move_to_lru_tail(&bo->ttm);
spin_unlock(&bo->ttm.bdev->lru_lock);
} else {
int ret = shrink_test_fill_random(bo, &prng, link);
if (ret) {
xe_bo_unlock(bo);
xe_bo_put(bo);
KUNIT_FAIL(test, "Error filling bo with random data: %pe\n",
ERR_PTR(ret));
kfree(link);
failed = true;
break;
}
}
mem_type = bo->ttm.resource->mem_type;
xe_bo_unlock(bo);
link->bo = bo;
list_add_tail(&link->link, &bos);
if (mem_type != XE_PL_TT) {
KUNIT_FAIL(test, "Bo in incorrect memory type: %u\n",
bo->ttm.resource->mem_type);
failed = true;
}
cond_resched();
if (signal_pending(current))
break;
}
/*
* Read back and destroy bos. Reset the pseudo-random seed to get an
* identical pseudo-random number sequence for readback.
*/
prandom_seed_state(&prng, rand_seed);
list_for_each_entry_safe(link, next, &bos, link) {
static struct ttm_operation_ctx ctx = {.interruptible = true};
struct xe_bo *bo = link->bo;
struct xe_ttm_tt *xe_tt;
int ret;
count++;
if (!signal_pending(current) && !failed) {
bool purgeable, intr = false;
xe_bo_lock(bo, NULL);
/* xe_tt->purgeable is cleared on validate. */
xe_tt = container_of(bo->ttm.ttm, typeof(*xe_tt), ttm);
purgeable = xe_tt->purgeable;
do {
ret = ttm_bo_validate(&bo->ttm, &tt_placement, &ctx);
if (ret == -EINTR)
intr = true;
} while (ret == -EINTR && !signal_pending(current));
if (!ret && !purgeable)
failed = shrink_test_verify(test, bo, count, &prng, link);
xe_bo_unlock(bo);
if (ret) {
KUNIT_FAIL(test, "Validation failed: %pe\n",
ERR_PTR(ret));
failed = true;
} else if (intr) {
interrupted++;
} else {
successful++;
}
}
xe_bo_put(link->bo);
list_del(&link->link);
kfree(link);
}
kunit_info(test, "Readbacks interrupted: %u successful: %u\n",
interrupted, successful);
return 0;
}
static void xe_bo_shrink_kunit(struct kunit *test)
{
struct xe_device *xe = test->priv;
shrink_test_run_device(xe);
}
static struct kunit_case xe_bo_tests[] = {
KUNIT_CASE_PARAM(xe_ccs_migrate_kunit, xe_pci_live_device_gen_param),
KUNIT_CASE_PARAM(xe_bo_evict_kunit, xe_pci_live_device_gen_param),
{}
};
VISIBLE_IF_KUNIT
struct kunit_suite xe_bo_test_suite = {
.name = "xe_bo",
.test_cases = xe_bo_tests,
.init = xe_kunit_helper_xe_device_live_test_init,
};
EXPORT_SYMBOL_IF_KUNIT(xe_bo_test_suite);
static struct kunit_case xe_bo_shrink_test[] = {
KUNIT_CASE_PARAM_ATTR(xe_bo_shrink_kunit, xe_pci_live_device_gen_param,
{.speed = KUNIT_SPEED_SLOW}),
{}
};
VISIBLE_IF_KUNIT
struct kunit_suite xe_bo_shrink_test_suite = {
.name = "xe_bo_shrink",
.test_cases = xe_bo_shrink_test,
.init = xe_kunit_helper_xe_device_live_test_init,
};
EXPORT_SYMBOL_IF_KUNIT(xe_bo_shrink_test_suite);
@@ -0,0 +1,299 @@
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2022 Intel Corporation
*/
#include <uapi/drm/xe_drm.h>
#include <kunit/test.h>
#include <kunit/visibility.h>
#include "tests/xe_kunit_helpers.h"
#include "tests/xe_pci_test.h"
#include "xe_pci.h"
#include "xe_pm.h"
static bool p2p_enabled(struct dma_buf_test_params *params)
{
return IS_ENABLED(CONFIG_PCI_P2PDMA) && params->attach_ops &&
params->attach_ops->allow_peer2peer;
}
static bool is_dynamic(struct dma_buf_test_params *params)
{
return params->attach_ops && params->attach_ops->invalidate_mappings;
}
static void check_residency(struct kunit *test, struct xe_bo *exported,
struct xe_bo *imported, struct dma_buf *dmabuf,
struct drm_exec *exec)
{
struct dma_buf_test_params *params = to_dma_buf_test_params(test->priv);
struct dma_buf_attachment *attach;
u32 mem_type;
int ret;
xe_bo_assert_held(exported);
xe_bo_assert_held(imported);
mem_type = XE_PL_VRAM0;
if (!(params->mem_mask & XE_BO_FLAG_VRAM0))
/* No VRAM allowed */
mem_type = XE_PL_TT;
else if (params->force_different_devices && !p2p_enabled(params))
/* No P2P */
mem_type = XE_PL_TT;
else if (params->force_different_devices && !is_dynamic(params) &&
(params->mem_mask & XE_BO_FLAG_SYSTEM))
/* Pin migrated to TT on non-dynamic attachments. */
mem_type = XE_PL_TT;
if (!xe_bo_is_mem_type(exported, mem_type)) {
KUNIT_FAIL(test, "Exported bo was not in expected memory type.\n");
return;
}
if (xe_bo_is_pinned(exported))
return;
/*
* Evict exporter. Evicting the exported bo will
* evict also the imported bo through the invalidate_mappings() functionality if
* importer is on a different device. If they're on the same device,
* the exporter and the importer should be the same bo.
*/
ret = xe_bo_evict(exported, exec);
if (ret) {
if (ret != -EINTR && ret != -ERESTARTSYS)
KUNIT_FAIL(test, "Evicting exporter failed with err=%d.\n",
ret);
return;
}
/* Verify that also importer has been evicted to SYSTEM */
if (exported != imported && !xe_bo_is_mem_type(imported, XE_PL_SYSTEM)) {
KUNIT_FAIL(test, "Importer wasn't properly evicted.\n");
return;
}
/* Re-validate the importer. This should move also exporter in. */
ret = xe_bo_validate(imported, NULL, false, exec);
if (ret) {
if (ret != -EINTR && ret != -ERESTARTSYS)
KUNIT_FAIL(test, "Validating importer failed with err=%d.\n",
ret);
return;
}
KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, mem_type));
/* Check that we can pin without migrating. */
attach = list_first_entry_or_null(&dmabuf->attachments, typeof(*attach), node);
if (attach) {
int err = dma_buf_pin(attach);
if (!err) {
KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(exported, mem_type));
dma_buf_unpin(attach);
}
KUNIT_EXPECT_EQ(test, err, 0);
}
if (params->force_different_devices)
KUNIT_EXPECT_TRUE(test, xe_bo_is_mem_type(imported, XE_PL_TT));
else
KUNIT_EXPECT_TRUE(test, exported == imported);
}
static void xe_test_dmabuf_import_same_driver(struct xe_device *xe)
{
struct kunit *test = kunit_get_current_test();
struct dma_buf_test_params *params = to_dma_buf_test_params(test->priv);
struct drm_gem_object *import;
struct dma_buf *dmabuf;
struct xe_bo *bo;
size_t size;
/* No VRAM on this device? */
if (!ttm_manager_type(&xe->ttm, XE_PL_VRAM0) &&
(params->mem_mask & XE_BO_FLAG_VRAM0))
return;
size = PAGE_SIZE;
if ((params->mem_mask & XE_BO_FLAG_VRAM0) &&
xe->info.vram_flags & XE_VRAM_FLAGS_NEED64K)
size = SZ_64K;
kunit_info(test, "running %s\n", __func__);
bo = xe_bo_create_user(xe, NULL, size, DRM_XE_GEM_CPU_CACHING_WC,
params->mem_mask, NULL);
if (IS_ERR(bo)) {
KUNIT_FAIL(test, "xe_bo_create() failed with err=%ld\n",
PTR_ERR(bo));
return;
}
dmabuf = xe_gem_prime_export(&bo->ttm.base, 0);
if (IS_ERR(dmabuf)) {
KUNIT_FAIL(test, "xe_gem_prime_export() failed with err=%ld\n",
PTR_ERR(dmabuf));
goto out;
}
bo->ttm.base.dma_buf = dmabuf;
import = xe_gem_prime_import(&xe->drm, dmabuf);
if (!IS_ERR(import)) {
struct xe_bo *import_bo = gem_to_xe_bo(import);
/*
* Did import succeed when it shouldn't due to lack of p2p support?
*/
if (params->force_different_devices &&
!p2p_enabled(params) &&
!(params->mem_mask & XE_BO_FLAG_SYSTEM)) {
KUNIT_FAIL(test,
"xe_gem_prime_import() succeeded when it shouldn't have\n");
} else {
struct drm_exec *exec = XE_VALIDATION_OPT_OUT;
int err;
/* Is everything where we expect it to be? */
xe_bo_lock(import_bo, false);
err = xe_bo_validate(import_bo, NULL, false, exec);
/* Pinning in VRAM is not allowed for non-dynamic attachments */
if (!is_dynamic(params) &&
params->force_different_devices &&
!(params->mem_mask & XE_BO_FLAG_SYSTEM))
KUNIT_EXPECT_EQ(test, err, -EINVAL);
/* Otherwise only expect interrupts or success. */
else if (err && err != -EINTR && err != -ERESTARTSYS)
KUNIT_EXPECT_TRUE(test, !err || err == -EINTR ||
err == -ERESTARTSYS);
if (!err)
check_residency(test, bo, import_bo, dmabuf, exec);
xe_bo_unlock(import_bo);
}
drm_gem_object_put(import);
} else if (PTR_ERR(import) != -EOPNOTSUPP) {
/* Unexpected error code. */
KUNIT_FAIL(test,
"xe_gem_prime_import failed with the wrong err=%ld\n",
PTR_ERR(import));
} else if (!params->force_different_devices ||
p2p_enabled(params) ||
(params->mem_mask & XE_BO_FLAG_SYSTEM)) {
/* Shouldn't fail if we can reuse same bo, use p2p or use system */
KUNIT_FAIL(test, "dynamic p2p attachment failed with err=%ld\n",
PTR_ERR(import));
}
bo->ttm.base.dma_buf = NULL;
dma_buf_put(dmabuf);
out:
drm_gem_object_put(&bo->ttm.base);
}
static const struct dma_buf_attach_ops nop2p_attach_ops = {
.allow_peer2peer = false,
.invalidate_mappings = xe_dma_buf_move_notify
};
/*
* We test the implementation with bos of different residency and with
* importers with different capabilities; some lacking p2p support and some
* lacking dynamic capabilities (attach_ops == NULL). We also fake
* different devices avoiding the import shortcut that just reuses the same
* gem object.
*/
static const struct dma_buf_test_params test_params[] = {
{.mem_mask = XE_BO_FLAG_VRAM0,
.attach_ops = &xe_dma_buf_attach_ops},
{.mem_mask = XE_BO_FLAG_VRAM0 | XE_BO_FLAG_NEEDS_CPU_ACCESS,
.attach_ops = &xe_dma_buf_attach_ops,
.force_different_devices = true},
{.mem_mask = XE_BO_FLAG_VRAM0,
.attach_ops = &nop2p_attach_ops},
{.mem_mask = XE_BO_FLAG_VRAM0,
.attach_ops = &nop2p_attach_ops,
.force_different_devices = true},
{.mem_mask = XE_BO_FLAG_VRAM0},
{.mem_mask = XE_BO_FLAG_VRAM0,
.force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM,
.attach_ops = &xe_dma_buf_attach_ops},
{.mem_mask = XE_BO_FLAG_SYSTEM,
.attach_ops = &xe_dma_buf_attach_ops,
.force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM,
.attach_ops = &nop2p_attach_ops},
{.mem_mask = XE_BO_FLAG_SYSTEM,
.attach_ops = &nop2p_attach_ops,
.force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM},
{.mem_mask = XE_BO_FLAG_SYSTEM,
.force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0,
.attach_ops = &xe_dma_buf_attach_ops},
{.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0 |
XE_BO_FLAG_NEEDS_CPU_ACCESS,
.attach_ops = &xe_dma_buf_attach_ops,
.force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0,
.attach_ops = &nop2p_attach_ops},
{.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0,
.attach_ops = &nop2p_attach_ops,
.force_different_devices = true},
{.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0},
{.mem_mask = XE_BO_FLAG_SYSTEM | XE_BO_FLAG_VRAM0,
.force_different_devices = true},
{}
};
static int dma_buf_run_device(struct xe_device *xe)
{
const struct dma_buf_test_params *params;
struct kunit *test = kunit_get_current_test();
guard(xe_pm_runtime)(xe);
for (params = test_params; params->mem_mask; ++params) {
struct dma_buf_test_params p = *params;
p.base.id = XE_TEST_LIVE_DMA_BUF;
test->priv = &p;
xe_test_dmabuf_import_same_driver(xe);
}
/* A non-zero return would halt iteration over driver devices */
return 0;
}
static void xe_dma_buf_kunit(struct kunit *test)
{
struct xe_device *xe = test->priv;
dma_buf_run_device(xe);
}
static struct kunit_case xe_dma_buf_tests[] = {
KUNIT_CASE_PARAM(xe_dma_buf_kunit, xe_pci_live_device_gen_param),
{}
};
VISIBLE_IF_KUNIT
struct kunit_suite xe_dma_buf_test_suite = {
.name = "xe_dma_buf",
.test_cases = xe_dma_buf_tests,
.init = xe_kunit_helper_xe_device_live_test_init,
};
EXPORT_SYMBOL_IF_KUNIT(xe_dma_buf_test_suite);
@@ -0,0 +1,319 @@
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2025 Intel Corporation
*/
#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <kunit/test-bug.h>
#include "xe_kunit_helpers.h"
#include "xe_pci_test.h"
#define TEST_MAX_VFS 63
#define TEST_VRAM 0x7a800000ull /* random size that works on 32-bit */
static bool xe_device_is_admin_only_stub_enable(const struct xe_device *xe)
{
return true;
}
static bool xe_device_is_admin_only_stub_disable(const struct xe_device *xe)
{
return false;
}
static void pf_set_admin_mode(struct xe_device *xe, bool enable)
{
typeof(xe_device_is_admin_only) *stub = enable ?
xe_device_is_admin_only_stub_enable :
xe_device_is_admin_only_stub_disable;
kunit_activate_static_stub(kunit_get_current_test(),
xe_device_is_admin_only,
*stub);
KUNIT_EXPECT_EQ(kunit_get_current_test(), enable, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_EQ(kunit_get_current_test(), enable, xe_device_is_admin_only(xe));
}
static void pf_set_usable_vram(struct xe_device *xe, u64 usable)
{
struct xe_tile *tile = xe_device_get_root_tile(xe);
struct kunit *test = kunit_get_current_test();
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tile);
xe->mem.vram->usable_size = usable;
tile->mem.vram->usable_size = usable;
KUNIT_ASSERT_EQ(test, usable, xe_vram_region_usable_size(tile->mem.vram));
}
static const void *num_vfs_gen_param(struct kunit *test, const void *prev, char *desc)
{
unsigned long next = 1 + (unsigned long)prev;
if (next > TEST_MAX_VFS)
return NULL;
snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%lu VF%s",
next, str_plural(next));
return (void *)next;
}
static int pf_gt_config_test_init(struct kunit *test)
{
struct xe_pci_fake_data fake = {
.sriov_mode = XE_SRIOV_MODE_PF,
.platform = XE_BATTLEMAGE, /* any random DGFX platform with SR-IOV */
.subplatform = XE_SUBPLATFORM_NONE,
.graphics_verx100 = 2001,
};
struct xe_vram_region *vram;
struct xe_device *xe;
struct xe_gt *gt;
test->priv = &fake;
xe_kunit_helper_xe_device_test_init(test);
xe = test->priv;
KUNIT_ASSERT_TRUE(test, IS_SRIOV_PF(xe));
gt = xe_root_mmio_gt(xe);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gt);
test->priv = gt;
/* pretend it has some VRAM */
KUNIT_ASSERT_TRUE(test, IS_DGFX(xe));
vram = kunit_kzalloc(test, sizeof(*vram), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, vram);
vram->usable_size = TEST_VRAM;
xe->mem.vram = vram;
xe->tiles[0].mem.vram = vram;
/* pretend we have a valid LMTT */
KUNIT_ASSERT_TRUE(test, xe_device_has_lmtt(xe));
KUNIT_ASSERT_GE(test, GRAPHICS_VERx100(xe), 1260);
xe->tiles[0].sriov.pf.lmtt.ops = &lmtt_ml_ops;
/* pretend it can support up to 63 VFs */
xe->sriov.pf.device_total_vfs = TEST_MAX_VFS;
xe->sriov.pf.driver_max_vfs = TEST_MAX_VFS;
KUNIT_ASSERT_EQ(test, xe_sriov_pf_get_totalvfs(xe), 63);
pf_set_admin_mode(xe, false);
KUNIT_ASSERT_EQ(test, xe_sriov_init(xe), 0);
/* more sanity checks */
KUNIT_EXPECT_EQ(test, GUC_ID_MAX + 1, SZ_64K);
KUNIT_EXPECT_EQ(test, GUC_NUM_DOORBELLS, SZ_256);
return 0;
}
static void fair_contexts_1vf(struct kunit *test)
{
struct xe_gt *gt = test->priv;
struct xe_device *xe = gt_to_xe(gt);
pf_set_admin_mode(xe, false);
KUNIT_ASSERT_FALSE(test, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_EQ(test, SZ_32K, pf_profile_fair_ctxs(gt, 1));
pf_set_admin_mode(xe, true);
KUNIT_ASSERT_TRUE(test, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_EQ(test, SZ_64K - SZ_1K, pf_profile_fair_ctxs(gt, 1));
}
static void fair_contexts(struct kunit *test)
{
unsigned int num_vfs = (unsigned long)test->param_value;
struct xe_gt *gt = test->priv;
struct xe_device *xe = gt_to_xe(gt);
pf_set_admin_mode(xe, false);
KUNIT_ASSERT_FALSE(test, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_TRUE(test, is_power_of_2(pf_profile_fair_ctxs(gt, num_vfs)));
KUNIT_EXPECT_GT(test, GUC_ID_MAX, num_vfs * pf_profile_fair_ctxs(gt, num_vfs));
if (num_vfs > 31)
KUNIT_ASSERT_EQ(test, SZ_1K, pf_profile_fair_ctxs(gt, num_vfs));
else if (num_vfs > 15)
KUNIT_ASSERT_EQ(test, SZ_2K, pf_profile_fair_ctxs(gt, num_vfs));
else if (num_vfs > 7)
KUNIT_ASSERT_EQ(test, SZ_4K, pf_profile_fair_ctxs(gt, num_vfs));
else if (num_vfs > 3)
KUNIT_ASSERT_EQ(test, SZ_8K, pf_profile_fair_ctxs(gt, num_vfs));
else if (num_vfs > 1)
KUNIT_ASSERT_EQ(test, SZ_16K, pf_profile_fair_ctxs(gt, num_vfs));
else
KUNIT_ASSERT_EQ(test, SZ_32K, pf_profile_fair_ctxs(gt, num_vfs));
}
static void fair_doorbells_1vf(struct kunit *test)
{
struct xe_gt *gt = test->priv;
struct xe_device *xe = gt_to_xe(gt);
pf_set_admin_mode(xe, false);
KUNIT_ASSERT_FALSE(test, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_EQ(test, 128, pf_profile_fair_dbs(gt, 1));
pf_set_admin_mode(xe, true);
KUNIT_ASSERT_TRUE(test, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_EQ(test, 240, pf_profile_fair_dbs(gt, 1));
}
static void fair_doorbells(struct kunit *test)
{
unsigned int num_vfs = (unsigned long)test->param_value;
struct xe_gt *gt = test->priv;
struct xe_device *xe = gt_to_xe(gt);
pf_set_admin_mode(xe, false);
KUNIT_ASSERT_FALSE(test, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_TRUE(test, is_power_of_2(pf_profile_fair_dbs(gt, num_vfs)));
KUNIT_EXPECT_GE(test, GUC_NUM_DOORBELLS, (num_vfs + 1) * pf_profile_fair_dbs(gt, num_vfs));
if (num_vfs > 31)
KUNIT_ASSERT_EQ(test, SZ_4, pf_profile_fair_dbs(gt, num_vfs));
else if (num_vfs > 15)
KUNIT_ASSERT_EQ(test, SZ_8, pf_profile_fair_dbs(gt, num_vfs));
else if (num_vfs > 7)
KUNIT_ASSERT_EQ(test, SZ_16, pf_profile_fair_dbs(gt, num_vfs));
else if (num_vfs > 3)
KUNIT_ASSERT_EQ(test, SZ_32, pf_profile_fair_dbs(gt, num_vfs));
else if (num_vfs > 1)
KUNIT_ASSERT_EQ(test, SZ_64, pf_profile_fair_dbs(gt, num_vfs));
else
KUNIT_ASSERT_EQ(test, SZ_128, pf_profile_fair_dbs(gt, num_vfs));
}
static void fair_ggtt_1vf(struct kunit *test)
{
struct xe_gt *gt = test->priv;
struct xe_device *xe = gt_to_xe(gt);
pf_set_admin_mode(xe, false);
KUNIT_ASSERT_FALSE(test, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_EQ(test, SZ_2G, pf_profile_fair_ggtt(gt, 1));
pf_set_admin_mode(xe, true);
KUNIT_ASSERT_TRUE(test, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_EQ(test, SZ_2G + SZ_1G + SZ_512M, pf_profile_fair_ggtt(gt, 1));
}
static void fair_ggtt(struct kunit *test)
{
unsigned int num_vfs = (unsigned long)test->param_value;
struct xe_gt *gt = test->priv;
struct xe_device *xe = gt_to_xe(gt);
u64 alignment = pf_get_ggtt_alignment(gt);
u64 shareable = SZ_2G + SZ_1G + SZ_512M;
pf_set_admin_mode(xe, false);
KUNIT_ASSERT_FALSE(test, xe_sriov_pf_admin_only(xe));
KUNIT_EXPECT_TRUE(test, IS_ALIGNED(pf_profile_fair_ggtt(gt, num_vfs), alignment));
KUNIT_EXPECT_GE(test, shareable, num_vfs * pf_profile_fair_ggtt(gt, num_vfs));
if (num_vfs > 56)
KUNIT_ASSERT_EQ(test, SZ_64M - SZ_8M, pf_profile_fair_ggtt(gt, num_vfs));
else if (num_vfs > 28)
KUNIT_ASSERT_EQ(test, SZ_64M, pf_profile_fair_ggtt(gt, num_vfs));
else if (num_vfs > 14)
KUNIT_ASSERT_EQ(test, SZ_128M, pf_profile_fair_ggtt(gt, num_vfs));
else if (num_vfs > 7)
KUNIT_ASSERT_EQ(test, SZ_256M, pf_profile_fair_ggtt(gt, num_vfs));
else if (num_vfs > 3)
KUNIT_ASSERT_EQ(test, SZ_512M, pf_profile_fair_ggtt(gt, num_vfs));
else if (num_vfs > 1)
KUNIT_ASSERT_EQ(test, SZ_1G, pf_profile_fair_ggtt(gt, num_vfs));
else
KUNIT_ASSERT_EQ(test, SZ_2G, pf_profile_fair_ggtt(gt, num_vfs));
}
static const u64 vram_sizes[] = {
SZ_4G - SZ_512M,
SZ_8G + SZ_4G - SZ_512M,
SZ_16G - SZ_512M,
SZ_32G - SZ_512M,
SZ_64G - SZ_512M,
TEST_VRAM,
};
static void u64_param_get_desc(const u64 *p, char *desc)
{
string_get_size(*p, 1, STRING_UNITS_2, desc, KUNIT_PARAM_DESC_SIZE);
}
KUNIT_ARRAY_PARAM(vram_size, vram_sizes, u64_param_get_desc);
static void fair_vram_1vf(struct kunit *test)
{
const u64 usable = *(const u64 *)test->param_value;
struct xe_gt *gt = test->priv;
struct xe_device *xe = gt_to_xe(gt);
pf_set_admin_mode(xe, false);
pf_set_usable_vram(xe, usable);
KUNIT_EXPECT_NE(test, 0, pf_profile_fair_lmem(gt, 1));
KUNIT_EXPECT_GE(test, usable, pf_profile_fair_lmem(gt, 1));
KUNIT_EXPECT_TRUE(test, is_power_of_2(pf_profile_fair_lmem(gt, 1)));
KUNIT_EXPECT_GE(test, usable - pf_profile_fair_lmem(gt, 1), pf_profile_fair_lmem(gt, 1));
}
static void fair_vram_1vf_admin_only(struct kunit *test)
{
const u64 usable = *(const u64 *)test->param_value;
struct xe_gt *gt = test->priv;
struct xe_device *xe = gt_to_xe(gt);
pf_set_admin_mode(xe, true);
pf_set_usable_vram(xe, usable);
KUNIT_EXPECT_NE(test, 0, pf_profile_fair_lmem(gt, 1));
KUNIT_EXPECT_GE(test, usable, pf_profile_fair_lmem(gt, 1));
KUNIT_EXPECT_LT(test, usable - pf_profile_fair_lmem(gt, 1), pf_profile_fair_lmem(gt, 1));
KUNIT_EXPECT_TRUE(test, IS_ALIGNED(pf_profile_fair_lmem(gt, 1), SZ_1G));
}
static void fair_vram(struct kunit *test)
{
unsigned int num_vfs = (unsigned long)test->param_value;
struct xe_gt *gt = test->priv;
struct xe_device *xe = gt_to_xe(gt);
u64 alignment = pf_get_lmem_alignment(gt);
char size[10];
pf_set_admin_mode(xe, false);
string_get_size(pf_profile_fair_lmem(gt, num_vfs), 1, STRING_UNITS_2, size, sizeof(size));
kunit_info(test, "fair %s %llx\n", size, pf_profile_fair_lmem(gt, num_vfs));
KUNIT_EXPECT_TRUE(test, is_power_of_2(pf_profile_fair_lmem(gt, num_vfs)));
KUNIT_EXPECT_TRUE(test, IS_ALIGNED(pf_profile_fair_lmem(gt, num_vfs), alignment));
KUNIT_EXPECT_GE(test, TEST_VRAM, num_vfs * pf_profile_fair_lmem(gt, num_vfs));
}
static struct kunit_case pf_gt_config_test_cases[] = {
KUNIT_CASE(fair_contexts_1vf),
KUNIT_CASE(fair_doorbells_1vf),
KUNIT_CASE(fair_ggtt_1vf),
KUNIT_CASE_PARAM(fair_vram_1vf, vram_size_gen_params),
KUNIT_CASE_PARAM(fair_vram_1vf_admin_only, vram_size_gen_params),
KUNIT_CASE_PARAM(fair_contexts, num_vfs_gen_param),
KUNIT_CASE_PARAM(fair_doorbells, num_vfs_gen_param),
KUNIT_CASE_PARAM(fair_ggtt, num_vfs_gen_param),
KUNIT_CASE_PARAM(fair_vram, num_vfs_gen_param),
{}
};
static struct kunit_suite pf_gt_config_suite = {
.name = "pf_gt_config",
.test_cases = pf_gt_config_test_cases,
.init = pf_gt_config_test_init,
};
kunit_test_suite(pf_gt_config_suite);
@@ -0,0 +1,329 @@
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2024 Intel Corporation
*/
#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <kunit/test-bug.h>
#include "xe_device.h"
#include "xe_ggtt.h"
#include "xe_guc_ct.h"
#include "xe_kunit_helpers.h"
#include "xe_pci_test.h"
#define DUT_GGTT_START SZ_1M
#define DUT_GGTT_SIZE SZ_2M
static struct xe_bo *replacement_xe_managed_bo_create_pin_map(struct xe_device *xe,
struct xe_tile *tile,
size_t size, u32 flags)
{
struct kunit *test = kunit_get_current_test();
struct xe_bo *bo;
void *buf;
bo = drmm_kzalloc(&xe->drm, sizeof(*bo), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo);
buf = drmm_kzalloc(&xe->drm, size, GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, buf);
bo->tile = tile;
bo->ttm.bdev = &xe->ttm;
bo->ttm.base.size = size;
iosys_map_set_vaddr(&bo->vmap, buf);
if (flags & XE_BO_FLAG_GGTT) {
struct xe_ggtt *ggtt = tile->mem.ggtt;
bo->ggtt_node[tile->id] = xe_ggtt_insert_node(ggtt, xe_bo_size(bo), SZ_4K);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo->ggtt_node[tile->id]);
}
return bo;
}
static int guc_buf_test_init(struct kunit *test)
{
struct xe_pci_fake_data fake = {
.sriov_mode = XE_SRIOV_MODE_PF,
.platform = XE_TIGERLAKE, /* some random platform */
.subplatform = XE_SUBPLATFORM_NONE,
};
struct xe_ggtt *ggtt;
struct xe_guc *guc;
test->priv = &fake;
xe_kunit_helper_xe_device_test_init(test);
ggtt = xe_device_get_root_tile(test->priv)->mem.ggtt;
guc = &xe_device_get_gt(test->priv, 0)->uc.guc;
KUNIT_ASSERT_EQ(test, 0,
xe_ggtt_init_kunit(ggtt, DUT_GGTT_START,
DUT_GGTT_SIZE));
kunit_activate_static_stub(test, xe_managed_bo_create_pin_map,
replacement_xe_managed_bo_create_pin_map);
KUNIT_ASSERT_EQ(test, 0, xe_guc_buf_cache_init(&guc->buf));
test->priv = &guc->buf;
return 0;
}
static void test_smallest(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf buf;
buf = xe_guc_buf_reserve(cache, 1);
KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf));
KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf));
KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf));
KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf));
xe_guc_buf_release(buf);
}
static void test_largest(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf buf;
buf = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache));
KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf));
KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf));
KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf));
KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf));
xe_guc_buf_release(buf);
}
static void test_granular(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf *bufs;
int n, dwords;
dwords = xe_guc_buf_cache_dwords(cache);
bufs = kunit_kcalloc(test, dwords, sizeof(*bufs), GFP_KERNEL);
KUNIT_EXPECT_NOT_NULL(test, bufs);
for (n = 0; n < dwords; n++)
bufs[n] = xe_guc_buf_reserve(cache, 1);
for (n = 0; n < dwords; n++)
KUNIT_EXPECT_TRUE_MSG(test, xe_guc_buf_is_valid(bufs[n]), "n=%d", n);
for (n = 0; n < dwords; n++)
xe_guc_buf_release(bufs[n]);
}
static void test_unique(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf *bufs;
int n, m, dwords;
dwords = xe_guc_buf_cache_dwords(cache);
bufs = kunit_kcalloc(test, dwords, sizeof(*bufs), GFP_KERNEL);
KUNIT_EXPECT_NOT_NULL(test, bufs);
for (n = 0; n < dwords; n++)
bufs[n] = xe_guc_buf_reserve(cache, 1);
for (n = 0; n < dwords; n++) {
for (m = n + 1; m < dwords; m++) {
KUNIT_EXPECT_PTR_NE_MSG(test, xe_guc_buf_cpu_ptr(bufs[n]),
xe_guc_buf_cpu_ptr(bufs[m]), "n=%d, m=%d", n, m);
KUNIT_ASSERT_NE_MSG(test, xe_guc_buf_gpu_addr(bufs[n]),
xe_guc_buf_gpu_addr(bufs[m]), "n=%d, m=%d", n, m);
}
}
for (n = 0; n < dwords; n++)
xe_guc_buf_release(bufs[n]);
}
static void test_overlap(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf b1, b2;
u32 dwords = xe_guc_buf_cache_dwords(cache) / 2;
u32 bytes = dwords * sizeof(u32);
void *p1, *p2;
u64 a1, a2;
b1 = xe_guc_buf_reserve(cache, dwords);
b2 = xe_guc_buf_reserve(cache, dwords);
p1 = xe_guc_buf_cpu_ptr(b1);
p2 = xe_guc_buf_cpu_ptr(b2);
a1 = xe_guc_buf_gpu_addr(b1);
a2 = xe_guc_buf_gpu_addr(b2);
KUNIT_EXPECT_PTR_NE(test, p1, p2);
if (p1 < p2)
KUNIT_EXPECT_LT(test, (uintptr_t)(p1 + bytes - 1), (uintptr_t)p2);
else
KUNIT_EXPECT_LT(test, (uintptr_t)(p2 + bytes - 1), (uintptr_t)p1);
KUNIT_EXPECT_NE(test, a1, a2);
if (a1 < a2)
KUNIT_EXPECT_LT(test, a1 + bytes - 1, a2);
else
KUNIT_EXPECT_LT(test, a2 + bytes - 1, a1);
xe_guc_buf_release(b1);
xe_guc_buf_release(b2);
}
static void test_reusable(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf b1, b2;
void *p1;
u64 a1;
b1 = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache));
KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(b1));
KUNIT_EXPECT_NOT_NULL(test, p1 = xe_guc_buf_cpu_ptr(b1));
KUNIT_EXPECT_NE(test, 0, a1 = xe_guc_buf_gpu_addr(b1));
xe_guc_buf_release(b1);
b2 = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache));
KUNIT_EXPECT_PTR_EQ(test, p1, xe_guc_buf_cpu_ptr(b2));
KUNIT_EXPECT_EQ(test, a1, xe_guc_buf_gpu_addr(b2));
xe_guc_buf_release(b2);
}
static void test_too_big(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf buf;
buf = xe_guc_buf_reserve(cache, xe_guc_buf_cache_dwords(cache) + 1);
KUNIT_EXPECT_FALSE(test, xe_guc_buf_is_valid(buf));
xe_guc_buf_release(buf); /* shouldn't crash */
}
static void test_flush(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf buf;
const u32 dwords = xe_guc_buf_cache_dwords(cache);
const u32 bytes = dwords * sizeof(u32);
u32 *s, *p, *d;
int n;
KUNIT_ASSERT_NOT_NULL(test, s = kunit_kcalloc(test, dwords, sizeof(u32), GFP_KERNEL));
KUNIT_ASSERT_NOT_NULL(test, d = kunit_kcalloc(test, dwords, sizeof(u32), GFP_KERNEL));
for (n = 0; n < dwords; n++)
s[n] = n;
buf = xe_guc_buf_reserve(cache, dwords);
KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
KUNIT_ASSERT_NOT_NULL(test, p = xe_guc_buf_cpu_ptr(buf));
KUNIT_EXPECT_PTR_NE(test, p, s);
KUNIT_EXPECT_PTR_NE(test, p, d);
memcpy(p, s, bytes);
KUNIT_EXPECT_NE(test, 0, xe_guc_buf_flush(buf));
iosys_map_memcpy_from(d, &cache->sam->bo->vmap, 0, bytes);
KUNIT_EXPECT_MEMEQ(test, s, d, bytes);
xe_guc_buf_release(buf);
}
static void test_lookup(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf buf;
u32 dwords;
u64 addr;
u32 *p;
int n;
dwords = xe_guc_buf_cache_dwords(cache);
buf = xe_guc_buf_reserve(cache, dwords);
KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
KUNIT_ASSERT_NOT_NULL(test, p = xe_guc_buf_cpu_ptr(buf));
KUNIT_ASSERT_NE(test, 0, addr = xe_guc_buf_gpu_addr(buf));
KUNIT_EXPECT_EQ(test, 0, xe_guc_cache_gpu_addr_from_ptr(cache, p - 1, sizeof(u32)));
KUNIT_EXPECT_EQ(test, 0, xe_guc_cache_gpu_addr_from_ptr(cache, p + dwords, sizeof(u32)));
for (n = 0; n < dwords; n++)
KUNIT_EXPECT_EQ_MSG(test, xe_guc_cache_gpu_addr_from_ptr(cache, p + n, sizeof(u32)),
addr + n * sizeof(u32), "n=%d", n);
xe_guc_buf_release(buf);
}
static void test_data(struct kunit *test)
{
static const u32 data[] = { 1, 2, 3, 4, 5, 6 };
struct xe_guc_buf_cache *cache = test->priv;
struct xe_guc_buf buf;
void *p;
buf = xe_guc_buf_from_data(cache, data, sizeof(data));
KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
KUNIT_ASSERT_NOT_NULL(test, p = xe_guc_buf_cpu_ptr(buf));
KUNIT_EXPECT_MEMEQ(test, p, data, sizeof(data));
xe_guc_buf_release(buf);
}
static void test_class(struct kunit *test)
{
struct xe_guc_buf_cache *cache = test->priv;
u32 dwords = xe_guc_buf_cache_dwords(cache);
{
CLASS(xe_guc_buf, buf)(cache, dwords);
KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf));
KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf));
KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf));
KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf));
}
{
CLASS(xe_guc_buf, buf)(cache, dwords);
KUNIT_ASSERT_TRUE(test, xe_guc_buf_is_valid(buf));
KUNIT_EXPECT_NOT_NULL(test, xe_guc_buf_cpu_ptr(buf));
KUNIT_EXPECT_NE(test, 0, xe_guc_buf_gpu_addr(buf));
KUNIT_EXPECT_LE(test, DUT_GGTT_START, xe_guc_buf_gpu_addr(buf));
KUNIT_EXPECT_GT(test, DUT_GGTT_START + DUT_GGTT_SIZE, xe_guc_buf_gpu_addr(buf));
}
}
static struct kunit_case guc_buf_test_cases[] = {
KUNIT_CASE(test_smallest),
KUNIT_CASE(test_largest),
KUNIT_CASE(test_granular),
KUNIT_CASE(test_unique),
KUNIT_CASE(test_overlap),
KUNIT_CASE(test_reusable),
KUNIT_CASE(test_too_big),
KUNIT_CASE(test_flush),
KUNIT_CASE(test_lookup),
KUNIT_CASE(test_data),
KUNIT_CASE(test_class),
{}
};
static struct kunit_suite guc_buf_suite = {
.name = "guc_buf",
.test_cases = guc_buf_test_cases,
.init = guc_buf_test_init,
};
kunit_test_suites(&guc_buf_suite);
@@ -0,0 +1,201 @@
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2023 Intel Corporation
*/
#include <kunit/test.h>
#include "xe_device.h"
#include "xe_kunit_helpers.h"
static int guc_dbm_test_init(struct kunit *test)
{
struct xe_guc_db_mgr *dbm;
xe_kunit_helper_xe_device_test_init(test);
dbm = &xe_device_get_gt(test->priv, 0)->uc.guc.dbm;
mutex_init(dbm_mutex(dbm));
test->priv = dbm;
return 0;
}
static void test_empty(struct kunit *test)
{
struct xe_guc_db_mgr *dbm = test->priv;
KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, 0), 0);
KUNIT_ASSERT_EQ(test, dbm->count, 0);
mutex_lock(dbm_mutex(dbm));
KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0);
mutex_unlock(dbm_mutex(dbm));
KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0);
}
static void test_default(struct kunit *test)
{
struct xe_guc_db_mgr *dbm = test->priv;
KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, ~0), 0);
KUNIT_ASSERT_EQ(test, dbm->count, GUC_NUM_DOORBELLS);
}
static const unsigned int guc_dbm_params[] = {
GUC_NUM_DOORBELLS / 64,
GUC_NUM_DOORBELLS / 32,
GUC_NUM_DOORBELLS / 8,
GUC_NUM_DOORBELLS,
};
static void uint_param_get_desc(const unsigned int *p, char *desc)
{
snprintf(desc, KUNIT_PARAM_DESC_SIZE, "%u", *p);
}
KUNIT_ARRAY_PARAM(guc_dbm, guc_dbm_params, uint_param_get_desc);
static void test_size(struct kunit *test)
{
const unsigned int *p = test->param_value;
struct xe_guc_db_mgr *dbm = test->priv;
unsigned int n;
int id;
KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, *p), 0);
KUNIT_ASSERT_EQ(test, dbm->count, *p);
mutex_lock(dbm_mutex(dbm));
for (n = 0; n < *p; n++) {
KUNIT_EXPECT_GE(test, id = xe_guc_db_mgr_reserve_id_locked(dbm), 0);
KUNIT_EXPECT_LT(test, id, dbm->count);
}
KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0);
mutex_unlock(dbm_mutex(dbm));
mutex_lock(dbm_mutex(dbm));
for (n = 0; n < *p; n++)
xe_guc_db_mgr_release_id_locked(dbm, n);
mutex_unlock(dbm_mutex(dbm));
}
static void test_reuse(struct kunit *test)
{
const unsigned int *p = test->param_value;
struct xe_guc_db_mgr *dbm = test->priv;
unsigned int n;
KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, *p), 0);
mutex_lock(dbm_mutex(dbm));
for (n = 0; n < *p; n++)
KUNIT_EXPECT_GE(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0);
KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0);
mutex_unlock(dbm_mutex(dbm));
mutex_lock(dbm_mutex(dbm));
for (n = 0; n < *p; n++) {
xe_guc_db_mgr_release_id_locked(dbm, n);
KUNIT_EXPECT_EQ(test, xe_guc_db_mgr_reserve_id_locked(dbm), n);
}
KUNIT_EXPECT_LT(test, xe_guc_db_mgr_reserve_id_locked(dbm), 0);
mutex_unlock(dbm_mutex(dbm));
mutex_lock(dbm_mutex(dbm));
for (n = 0; n < *p; n++)
xe_guc_db_mgr_release_id_locked(dbm, n);
mutex_unlock(dbm_mutex(dbm));
}
static void test_range_overlap(struct kunit *test)
{
const unsigned int *p = test->param_value;
struct xe_guc_db_mgr *dbm = test->priv;
int id1, id2, id3;
unsigned int n;
KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, ~0), 0);
KUNIT_ASSERT_LE(test, *p, dbm->count);
KUNIT_ASSERT_GE(test, id1 = xe_guc_db_mgr_reserve_range(dbm, *p, 0), 0);
for (n = 0; n < dbm->count - *p; n++) {
KUNIT_ASSERT_GE(test, id2 = xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0);
KUNIT_ASSERT_NE(test, id2, id1);
KUNIT_ASSERT_NE_MSG(test, id2 < id1, id2 > id1 + *p - 1,
"id1=%d id2=%d", id1, id2);
}
KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0);
xe_guc_db_mgr_release_range(dbm, 0, dbm->count);
if (*p >= 1) {
KUNIT_ASSERT_GE(test, id1 = xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0);
KUNIT_ASSERT_GE(test, id2 = xe_guc_db_mgr_reserve_range(dbm, *p - 1, 0), 0);
KUNIT_ASSERT_NE(test, id2, id1);
KUNIT_ASSERT_NE_MSG(test, id1 < id2, id1 > id2 + *p - 2,
"id1=%d id2=%d", id1, id2);
for (n = 0; n < dbm->count - *p; n++) {
KUNIT_ASSERT_GE(test, id3 = xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0);
KUNIT_ASSERT_NE(test, id3, id1);
KUNIT_ASSERT_NE(test, id3, id2);
KUNIT_ASSERT_NE_MSG(test, id3 < id2, id3 > id2 + *p - 2,
"id3=%d id2=%d", id3, id2);
}
KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0);
xe_guc_db_mgr_release_range(dbm, 0, dbm->count);
}
}
static void test_range_compact(struct kunit *test)
{
const unsigned int *p = test->param_value;
struct xe_guc_db_mgr *dbm = test->priv;
unsigned int n;
KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, ~0), 0);
KUNIT_ASSERT_NE(test, *p, 0);
KUNIT_ASSERT_LE(test, *p, dbm->count);
if (dbm->count % *p)
kunit_skip(test, "must be divisible");
KUNIT_ASSERT_GE(test, xe_guc_db_mgr_reserve_range(dbm, *p, 0), 0);
for (n = 1; n < dbm->count / *p; n++)
KUNIT_ASSERT_GE(test, xe_guc_db_mgr_reserve_range(dbm, *p, 0), 0);
KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, 0), 0);
xe_guc_db_mgr_release_range(dbm, 0, dbm->count);
}
static void test_range_spare(struct kunit *test)
{
const unsigned int *p = test->param_value;
struct xe_guc_db_mgr *dbm = test->priv;
int id;
KUNIT_ASSERT_EQ(test, xe_guc_db_mgr_init(dbm, ~0), 0);
KUNIT_ASSERT_LE(test, *p, dbm->count);
KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, *p, dbm->count), 0);
KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, *p, dbm->count - *p + 1), 0);
KUNIT_ASSERT_EQ(test, id = xe_guc_db_mgr_reserve_range(dbm, *p, dbm->count - *p), 0);
KUNIT_ASSERT_LT(test, xe_guc_db_mgr_reserve_range(dbm, 1, dbm->count - *p), 0);
xe_guc_db_mgr_release_range(dbm, id, *p);
}
static struct kunit_case guc_dbm_test_cases[] = {
KUNIT_CASE(test_empty),
KUNIT_CASE(test_default),
KUNIT_CASE_PARAM(test_size, guc_dbm_gen_params),
KUNIT_CASE_PARAM(test_reuse, guc_dbm_gen_params),
KUNIT_CASE_PARAM(test_range_overlap, guc_dbm_gen_params),
KUNIT_CASE_PARAM(test_range_compact, guc_dbm_gen_params),
KUNIT_CASE_PARAM(test_range_spare, guc_dbm_gen_params),
{}
};
static struct kunit_suite guc_dbm_suite = {
.name = "guc_dbm",
.test_cases = guc_dbm_test_cases,
.init = guc_dbm_test_init,
};
kunit_test_suites(&guc_dbm_suite);
@@ -0,0 +1,833 @@
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2025 Intel Corporation
*/
#include <linux/delay.h>
#include <kunit/test.h>
#include <kunit/visibility.h>
#include "tests/xe_kunit_helpers.h"
#include "tests/xe_pci_test.h"
#include "tests/xe_test.h"
#include "xe_bo.h"
#include "xe_device.h"
#include "xe_pm.h"
/*
* There are different ways to allocate the G2G buffers. The plan for this test
* is to make sure that all the possible options work. The particular option
* chosen by the driver may vary from one platform to another, it may also change
* with time. So to ensure consistency of testing, the relevant driver code is
* replicated here to guarantee it won't change without the test being updated
* to keep testing the other options.
*
* In order to test the actual code being used by the driver, there is also the
* 'default' scheme. That will use the official driver routines to test whatever
* method the driver is using on the current platform at the current time.
*/
enum {
/* Driver defined allocation scheme */
G2G_CTB_TYPE_DEFAULT,
/* Single buffer in host memory */
G2G_CTB_TYPE_HOST,
/* Single buffer in a specific tile, loops across all tiles */
G2G_CTB_TYPE_TILE,
};
/*
* Payload is opaque to GuC. So KMD can define any structure or size it wants.
*/
struct g2g_test_payload {
u32 tx_dev;
u32 tx_tile;
u32 rx_dev;
u32 rx_tile;
u32 seqno;
};
static int slot_index_from_gts(struct xe_gt *tx_gt, struct xe_gt *rx_gt)
{
struct xe_device *xe = gt_to_xe(tx_gt);
int idx = 0, found = 0, id, tx_idx, rx_idx;
struct xe_gt *gt;
struct kunit *test = kunit_get_current_test();
for (id = 0; id < xe->info.tile_count * xe->info.max_gt_per_tile; id++) {
gt = xe_device_get_gt(xe, id);
if (!gt)
continue;
if (gt == tx_gt) {
tx_idx = idx;
found++;
}
if (gt == rx_gt) {
rx_idx = idx;
found++;
}
if (found == 2)
break;
idx++;
}
if (found != 2)
KUNIT_FAIL(test, "GT index not found");
return (tx_idx * xe->info.gt_count) + rx_idx;
}
static void g2g_test_send(struct kunit *test, struct xe_guc *guc,
u32 far_tile, u32 far_dev,
struct g2g_test_payload *payload)
{
struct xe_device *xe = guc_to_xe(guc);
struct xe_gt *gt = guc_to_gt(guc);
u32 *action, total;
size_t payload_len;
int ret;
static_assert(IS_ALIGNED(sizeof(*payload), sizeof(u32)));
payload_len = sizeof(*payload) / sizeof(u32);
total = 4 + payload_len;
action = kunit_kmalloc_array(test, total, sizeof(*action), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, action);
action[0] = XE_GUC_ACTION_TEST_G2G_SEND;
action[1] = far_tile;
action[2] = far_dev;
action[3] = payload_len;
memcpy(action + 4, payload, payload_len * sizeof(u32));
atomic_inc(&xe->g2g_test_count);
/*
* Should specify the expected response notification here. Problem is that
* the response will be coming from a different GuC. By the end, it should
* all add up as long as an equal number of messages are sent from each GuC
* and to each GuC. However, in the middle negative reservation space errors
* and such like can occur. Rather than add intrusive changes to the CT layer
* it is simpler to just not bother counting it at all. The system should be
* idle when running the selftest, and the selftest's notification total size
* is well within the G2H allocation size. So there should be no issues with
* needing to block for space, which is all the tracking code is really for.
*/
ret = xe_guc_ct_send(&guc->ct, action, total, 0, 0);
kunit_kfree(test, action);
KUNIT_ASSERT_EQ_MSG(test, 0, ret, "G2G send failed: %d [%d:%d -> %d:%d]\n", ret,
gt_to_tile(gt)->id, G2G_DEV(gt), far_tile, far_dev);
}
/*
* NB: Can't use KUNIT_ASSERT and friends in here as this is called asynchronously
* from the G2H notification handler. Need that to actually complete rather than
* thread-abort in order to keep the rest of the driver alive!
*/
int xe_guc_g2g_test_notification(struct xe_guc *guc, u32 *msg, u32 len)
{
struct xe_device *xe = guc_to_xe(guc);
struct xe_gt *rx_gt = guc_to_gt(guc), *test_gt, *tx_gt = NULL;
u32 tx_tile, tx_dev, rx_tile, rx_dev, idx, got_len;
struct g2g_test_payload *payload;
size_t payload_len;
int ret = 0, i;
payload_len = sizeof(*payload) / sizeof(u32);
if (unlikely(len != (G2H_LEN_DW_G2G_NOTIFY_MIN + payload_len))) {
xe_gt_err(rx_gt, "G2G test notification invalid length %u", len);
ret = -EPROTO;
goto done;
}
tx_tile = msg[0];
tx_dev = msg[1];
got_len = msg[2];
payload = (struct g2g_test_payload *)(msg + 3);
rx_tile = gt_to_tile(rx_gt)->id;
rx_dev = G2G_DEV(rx_gt);
if (got_len != payload_len) {
xe_gt_err(rx_gt, "G2G: Invalid payload length: %u vs %zu\n", got_len, payload_len);
ret = -EPROTO;
goto done;
}
if (payload->tx_dev != tx_dev || payload->tx_tile != tx_tile ||
payload->rx_dev != rx_dev || payload->rx_tile != rx_tile) {
xe_gt_err(rx_gt, "G2G: Invalid payload: %d:%d -> %d:%d vs %d:%d -> %d:%d! [%d]\n",
payload->tx_tile, payload->tx_dev, payload->rx_tile, payload->rx_dev,
tx_tile, tx_dev, rx_tile, rx_dev, payload->seqno);
ret = -EPROTO;
goto done;
}
if (!xe->g2g_test_array) {
xe_gt_err(rx_gt, "G2G: Missing test array!\n");
ret = -ENOMEM;
goto done;
}
for_each_gt(test_gt, xe, i) {
if (gt_to_tile(test_gt)->id != tx_tile)
continue;
if (G2G_DEV(test_gt) != tx_dev)
continue;
if (tx_gt) {
xe_gt_err(rx_gt, "G2G: Got duplicate TX GTs: %d vs %d for %d:%d!\n",
tx_gt->info.id, test_gt->info.id, tx_tile, tx_dev);
ret = -EINVAL;
goto done;
}
tx_gt = test_gt;
}
if (!tx_gt) {
xe_gt_err(rx_gt, "G2G: Failed to find a TX GT for %d:%d!\n", tx_tile, tx_dev);
ret = -EINVAL;
goto done;
}
idx = slot_index_from_gts(tx_gt, rx_gt);
if (xe->g2g_test_array[idx] != payload->seqno - 1) {
xe_gt_err(rx_gt, "G2G: Seqno mismatch %d vs %d for %d:%d -> %d:%d!\n",
xe->g2g_test_array[idx], payload->seqno - 1,
tx_tile, tx_dev, rx_tile, rx_dev);
ret = -EINVAL;
goto done;
}
xe->g2g_test_array[idx] = payload->seqno;
done:
atomic_dec(&xe->g2g_test_count);
return ret;
}
#define G2G_WAIT_TIMEOUT_MS 100
#define G2G_WAIT_POLL_MS 1
/*
* Send the given seqno from all GuCs to all other GuCs in tile/GT order
*/
static void g2g_test_in_order(struct kunit *test, struct xe_device *xe, u32 seqno)
{
struct xe_gt *near_gt, *far_gt;
int i, j, waited;
u32 idx;
for_each_gt(near_gt, xe, i) {
u32 near_tile = gt_to_tile(near_gt)->id;
u32 near_dev = G2G_DEV(near_gt);
for_each_gt(far_gt, xe, j) {
u32 far_tile = gt_to_tile(far_gt)->id;
u32 far_dev = G2G_DEV(far_gt);
struct g2g_test_payload payload;
if (far_gt->info.id == near_gt->info.id)
continue;
payload.tx_dev = near_dev;
payload.tx_tile = near_tile;
payload.rx_dev = far_dev;
payload.rx_tile = far_tile;
payload.seqno = seqno;
/* Calculate idx for event-based wait */
idx = slot_index_from_gts(near_gt, far_gt);
waited = 0;
/*
* Wait for previous seqno to be acknowledged before sending,
* to avoid queuing too many back-to-back messages and
* causing a test timeout. Actual correctness of message
* will be checked later in xe_guc_g2g_test_notification()
*/
while (xe->g2g_test_array[idx] != (seqno - 1)) {
msleep(G2G_WAIT_POLL_MS);
waited += G2G_WAIT_POLL_MS;
if (waited >= G2G_WAIT_TIMEOUT_MS) {
kunit_info(test, "Timeout waiting! tx gt: %d, rx gt: %d\n",
near_gt->info.id, far_gt->info.id);
break;
}
}
g2g_test_send(test, &near_gt->uc.guc, far_tile, far_dev, &payload);
}
}
}
#define WAIT_TIME_MS 100
#define WAIT_COUNT (1000 / WAIT_TIME_MS)
static void g2g_wait_for_complete(void *_xe)
{
struct xe_device *xe = (struct xe_device *)_xe;
struct kunit *test = kunit_get_current_test();
int wait = 0;
/* Wait for all G2H messages to be received */
while (atomic_read(&xe->g2g_test_count)) {
if (++wait > WAIT_COUNT)
break;
msleep(WAIT_TIME_MS);
}
KUNIT_ASSERT_EQ_MSG(test, 0, atomic_read(&xe->g2g_test_count),
"Timed out waiting for notifications\n");
kunit_info(test, "Got all notifications back\n");
}
#undef WAIT_TIME_MS
#undef WAIT_COUNT
static void g2g_clean_array(void *_xe)
{
struct xe_device *xe = (struct xe_device *)_xe;
xe->g2g_test_array = NULL;
}
#define NUM_LOOPS 16
static void g2g_run_test(struct kunit *test, struct xe_device *xe)
{
u32 seqno, max_array;
int ret, i, j;
max_array = xe->info.gt_count * xe->info.gt_count;
xe->g2g_test_array = kunit_kcalloc(test, max_array, sizeof(u32), GFP_KERNEL);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe->g2g_test_array);
ret = kunit_add_action_or_reset(test, g2g_clean_array, xe);
KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register clean up action\n");
/*
* Send incrementing seqnos from all GuCs to all other GuCs in tile/GT order.
* Tile/GT order doesn't really mean anything to the hardware but it is going
* to be a fixed sequence every time.
*
* Verify that each one comes back having taken the correct route.
*/
ret = kunit_add_action(test, g2g_wait_for_complete, xe);
KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register clean up action\n");
for (seqno = 1; seqno < NUM_LOOPS; seqno++)
g2g_test_in_order(test, xe, seqno);
seqno--;
kunit_release_action(test, &g2g_wait_for_complete, xe);
/* Check for the final seqno in each slot */
for (i = 0; i < xe->info.gt_count; i++) {
for (j = 0; j < xe->info.gt_count; j++) {
u32 idx = (j * xe->info.gt_count) + i;
if (i == j)
KUNIT_ASSERT_EQ_MSG(test, 0, xe->g2g_test_array[idx],
"identity seqno modified: %d for %dx%d!\n",
xe->g2g_test_array[idx], i, j);
else
KUNIT_ASSERT_EQ_MSG(test, seqno, xe->g2g_test_array[idx],
"invalid seqno: %d vs %d for %dx%d!\n",
xe->g2g_test_array[idx], seqno, i, j);
}
}
kunit_kfree(test, xe->g2g_test_array);
kunit_release_action(test, &g2g_clean_array, xe);
kunit_info(test, "Test passed\n");
}
#undef NUM_LOOPS
static void g2g_ct_stop(struct xe_guc *guc)
{
struct xe_gt *remote_gt, *gt = guc_to_gt(guc);
struct xe_device *xe = gt_to_xe(gt);
int i, t;
for_each_gt(remote_gt, xe, i) {
u32 tile, dev;
if (remote_gt->info.id == gt->info.id)
continue;
tile = gt_to_tile(remote_gt)->id;
dev = G2G_DEV(remote_gt);
for (t = 0; t < XE_G2G_TYPE_LIMIT; t++)
guc_g2g_deregister(guc, tile, dev, t);
}
}
/* Size of a single allocation that contains all G2G CTBs across all GTs */
static u32 g2g_ctb_size(struct kunit *test, struct xe_device *xe)
{
unsigned int count = xe->info.gt_count;
u32 num_channels = (count * (count - 1)) / 2;
kunit_info(test, "Size: (%d * %d / 2) * %d * 0x%08X + 0x%08X => 0x%08X [%d]\n",
count, count - 1, XE_G2G_TYPE_LIMIT, G2G_BUFFER_SIZE, G2G_DESC_AREA_SIZE,
num_channels * XE_G2G_TYPE_LIMIT * G2G_BUFFER_SIZE + G2G_DESC_AREA_SIZE,
num_channels * XE_G2G_TYPE_LIMIT);
return num_channels * XE_G2G_TYPE_LIMIT * G2G_BUFFER_SIZE + G2G_DESC_AREA_SIZE;
}
/*
* Use the driver's regular CTB allocation scheme.
*/
static void g2g_alloc_default(struct kunit *test, struct xe_device *xe)
{
struct xe_gt *gt;
int i;
kunit_info(test, "Default [tiles = %d, GTs = %d]\n",
xe->info.tile_count, xe->info.gt_count);
for_each_gt(gt, xe, i) {
struct xe_guc *guc = &gt->uc.guc;
int ret;
ret = guc_g2g_alloc(guc);
KUNIT_ASSERT_EQ_MSG(test, 0, ret, "G2G alloc failed: %pe", ERR_PTR(ret));
continue;
}
}
static void g2g_distribute(struct kunit *test, struct xe_device *xe, struct xe_bo *bo)
{
struct xe_gt *root_gt, *gt;
int i;
root_gt = xe_device_get_gt(xe, 0);
root_gt->uc.guc.g2g.bo = bo;
root_gt->uc.guc.g2g.owned = true;
kunit_info(test, "[%d.%d] Assigned 0x%p\n", gt_to_tile(root_gt)->id, root_gt->info.id, bo);
for_each_gt(gt, xe, i) {
if (gt->info.id != 0) {
gt->uc.guc.g2g.owned = false;
gt->uc.guc.g2g.bo = xe_bo_get(bo);
kunit_info(test, "[%d.%d] Pinned 0x%p\n",
gt_to_tile(gt)->id, gt->info.id, gt->uc.guc.g2g.bo);
}
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, gt->uc.guc.g2g.bo);
}
}
/*
* Allocate a single blob on the host and split between all G2G CTBs.
*/
static void g2g_alloc_host(struct kunit *test, struct xe_device *xe)
{
struct xe_bo *bo;
u32 g2g_size;
kunit_info(test, "Host [tiles = %d, GTs = %d]\n", xe->info.tile_count, xe->info.gt_count);
g2g_size = g2g_ctb_size(test, xe);
bo = xe_managed_bo_create_pin_map(xe, xe_device_get_root_tile(xe), g2g_size,
XE_BO_FLAG_SYSTEM |
XE_BO_FLAG_GGTT |
XE_BO_FLAG_GGTT_ALL |
XE_BO_FLAG_GGTT_INVALIDATE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo);
kunit_info(test, "[HST] G2G buffer create: 0x%p\n", bo);
xe_map_memset(xe, &bo->vmap, 0, 0, g2g_size);
g2g_distribute(test, xe, bo);
}
/*
* Allocate a single blob on the given tile and split between all G2G CTBs.
*/
static void g2g_alloc_tile(struct kunit *test, struct xe_device *xe, struct xe_tile *tile)
{
struct xe_bo *bo;
u32 g2g_size;
KUNIT_ASSERT_TRUE(test, IS_DGFX(xe));
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, tile);
kunit_info(test, "Tile %d [tiles = %d, GTs = %d]\n",
tile->id, xe->info.tile_count, xe->info.gt_count);
g2g_size = g2g_ctb_size(test, xe);
bo = xe_managed_bo_create_pin_map(xe, tile, g2g_size,
XE_BO_FLAG_VRAM_IF_DGFX(tile) |
XE_BO_FLAG_GGTT |
XE_BO_FLAG_GGTT_ALL |
XE_BO_FLAG_GGTT_INVALIDATE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, bo);
kunit_info(test, "[%d.*] G2G buffer create: 0x%p\n", tile->id, bo);
xe_map_memset(xe, &bo->vmap, 0, 0, g2g_size);
g2g_distribute(test, xe, bo);
}
static void g2g_free(struct kunit *test, struct xe_device *xe)
{
struct xe_gt *gt;
struct xe_bo *bo;
int i;
for_each_gt(gt, xe, i) {
bo = gt->uc.guc.g2g.bo;
if (!bo)
continue;
if (gt->uc.guc.g2g.owned) {
xe_managed_bo_unpin_map_no_vm(bo);
kunit_info(test, "[%d.%d] Unmapped 0x%p\n",
gt_to_tile(gt)->id, gt->info.id, bo);
} else {
xe_bo_put(bo);
kunit_info(test, "[%d.%d] Unpinned 0x%p\n",
gt_to_tile(gt)->id, gt->info.id, bo);
}
gt->uc.guc.g2g.bo = NULL;
}
}
static void g2g_stop(struct kunit *test, struct xe_device *xe)
{
struct xe_gt *gt;
int i;
for_each_gt(gt, xe, i) {
struct xe_guc *guc = &gt->uc.guc;
if (!guc->g2g.bo)
continue;
g2g_ct_stop(guc);
}
g2g_free(test, xe);
}
/*
* Generate a unique id for each bi-directional CTB for each pair of
* near and far tiles/devices. The id can then be used as an index into
* a single allocation that is sub-divided into multiple CTBs.
*
* For example, with two devices per tile and two tiles, the table should
* look like:
* Far <tile>.<dev>
* 0.0 0.1 1.0 1.1
* N 0.0 --/-- 00/01 02/03 04/05
* e 0.1 01/00 --/-- 06/07 08/09
* a 1.0 03/02 07/06 --/-- 10/11
* r 1.1 05/04 09/08 11/10 --/--
*
* Where each entry is Rx/Tx channel id.
*
* So GuC #3 (tile 1, dev 1) talking to GuC #2 (tile 1, dev 0) would
* be reading from channel #11 and writing to channel #10. Whereas,
* GuC #2 talking to GuC #3 would be read on #10 and write to #11.
*/
static int g2g_slot_flat(u32 near_tile, u32 near_dev, u32 far_tile, u32 far_dev,
u32 type, u32 max_inst, bool have_dev)
{
u32 near = near_tile, far = far_tile;
u32 idx = 0, x, y, direction;
int i;
if (have_dev) {
near = (near << 1) | near_dev;
far = (far << 1) | far_dev;
}
/* No need to send to one's self */
if (far == near)
return -1;
if (far > near) {
/* Top right table half */
x = far;
y = near;
/* T/R is 'forwards' direction */
direction = type;
} else {
/* Bottom left table half */
x = near;
y = far;
/* B/L is 'backwards' direction */
direction = (1 - type);
}
/* Count the rows prior to the target */
for (i = y; i > 0; i--)
idx += max_inst - i;
/* Count this row up to the target */
idx += (x - 1 - y);
/* Slots are in Rx/Tx pairs */
idx *= 2;
/* Pick Rx/Tx direction */
idx += direction;
return idx;
}
static int g2g_register_flat(struct xe_guc *guc, u32 far_tile, u32 far_dev, u32 type, bool have_dev)
{
struct xe_gt *gt = guc_to_gt(guc);
struct xe_device *xe = gt_to_xe(gt);
u32 near_tile = gt_to_tile(gt)->id;
u32 near_dev = G2G_DEV(gt);
u32 max = xe->info.gt_count;
int idx;
u32 base, desc, buf;
if (!guc->g2g.bo)
return -ENODEV;
idx = g2g_slot_flat(near_tile, near_dev, far_tile, far_dev, type, max, have_dev);
xe_assert(xe, idx >= 0);
base = guc_bo_ggtt_addr(guc, guc->g2g.bo);
desc = base + idx * G2G_DESC_SIZE;
buf = base + idx * G2G_BUFFER_SIZE + G2G_DESC_AREA_SIZE;
xe_assert(xe, (desc - base + G2G_DESC_SIZE) <= G2G_DESC_AREA_SIZE);
xe_assert(xe, (buf - base + G2G_BUFFER_SIZE) <= xe_bo_size(guc->g2g.bo));
return guc_action_register_g2g_buffer(guc, type, far_tile, far_dev,
desc, buf, G2G_BUFFER_SIZE);
}
static void g2g_start(struct kunit *test, struct xe_guc *guc)
{
struct xe_gt *remote_gt, *gt = guc_to_gt(guc);
struct xe_device *xe = gt_to_xe(gt);
unsigned int i;
int t, ret;
bool have_dev;
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, guc->g2g.bo);
/* GuC interface will need extending if more GT device types are ever created. */
KUNIT_ASSERT_TRUE(test,
(gt->info.type == XE_GT_TYPE_MAIN) ||
(gt->info.type == XE_GT_TYPE_MEDIA));
/* Channel numbering depends on whether there are multiple GTs per tile */
have_dev = xe->info.gt_count > xe->info.tile_count;
for_each_gt(remote_gt, xe, i) {
u32 tile, dev;
if (remote_gt->info.id == gt->info.id)
continue;
tile = gt_to_tile(remote_gt)->id;
dev = G2G_DEV(remote_gt);
for (t = 0; t < XE_G2G_TYPE_LIMIT; t++) {
ret = g2g_register_flat(guc, tile, dev, t, have_dev);
KUNIT_ASSERT_EQ_MSG(test, 0, ret, "G2G register failed: %pe", ERR_PTR(ret));
}
}
}
static void g2g_reinit(struct kunit *test, struct xe_device *xe, int ctb_type, struct xe_tile *tile)
{
struct xe_gt *gt;
int i, found = 0;
g2g_stop(test, xe);
for_each_gt(gt, xe, i) {
struct xe_guc *guc = &gt->uc.guc;
KUNIT_ASSERT_NULL(test, guc->g2g.bo);
}
switch (ctb_type) {
case G2G_CTB_TYPE_DEFAULT:
g2g_alloc_default(test, xe);
break;
case G2G_CTB_TYPE_HOST:
g2g_alloc_host(test, xe);
break;
case G2G_CTB_TYPE_TILE:
g2g_alloc_tile(test, xe, tile);
break;
default:
KUNIT_ASSERT_TRUE(test, false);
}
for_each_gt(gt, xe, i) {
struct xe_guc *guc = &gt->uc.guc;
if (!guc->g2g.bo)
continue;
if (ctb_type == G2G_CTB_TYPE_DEFAULT)
guc_g2g_start(guc);
else
g2g_start(test, guc);
found++;
}
KUNIT_ASSERT_GT_MSG(test, found, 1, "insufficient G2G channels running: %d", found);
kunit_info(test, "Testing across %d GTs\n", found);
}
static void g2g_recreate_ctb(void *_xe)
{
struct xe_device *xe = (struct xe_device *)_xe;
struct kunit *test = kunit_get_current_test();
g2g_stop(test, xe);
if (xe_guc_g2g_wanted(xe))
g2g_reinit(test, xe, G2G_CTB_TYPE_DEFAULT, NULL);
}
static void g2g_pm_runtime_put(void *_xe)
{
struct xe_device *xe = (struct xe_device *)_xe;
xe_pm_runtime_put(xe);
}
static void g2g_pm_runtime_get(struct kunit *test)
{
struct xe_device *xe = test->priv;
int ret;
xe_pm_runtime_get(xe);
ret = kunit_add_action_or_reset(test, g2g_pm_runtime_put, xe);
KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register runtime PM action\n");
}
static void g2g_check_skip(struct kunit *test)
{
struct xe_device *xe = test->priv;
struct xe_gt *gt;
int i;
if (IS_SRIOV_VF(xe))
kunit_skip(test, "not supported from a VF");
if (xe->info.gt_count <= 1)
kunit_skip(test, "not enough GTs");
for_each_gt(gt, xe, i) {
struct xe_guc *guc = &gt->uc.guc;
if (guc->fw.build_type == CSS_UKERNEL_INFO_BUILDTYPE_PROD)
kunit_skip(test,
"G2G test interface not available in production firmware builds\n");
}
}
/*
* Simple test that does not try to recreate the CTBs.
* Requires that the platform already enables G2G comms
* but has no risk of leaving the system in a broken state
* afterwards.
*/
static void xe_live_guc_g2g_kunit_default(struct kunit *test)
{
struct xe_device *xe = test->priv;
if (!xe_guc_g2g_wanted(xe))
kunit_skip(test, "G2G not enabled");
g2g_check_skip(test);
g2g_pm_runtime_get(test);
kunit_info(test, "Testing default CTBs\n");
g2g_run_test(test, xe);
kunit_release_action(test, &g2g_pm_runtime_put, xe);
}
/*
* More complex test that re-creates the CTBs in various location to
* test access to each location from each GuC. Can be run even on
* systems that do not enable G2G by default. On the other hand,
* because it recreates the CTBs, if something goes wrong it could
* leave the system with broken G2G comms.
*/
static void xe_live_guc_g2g_kunit_allmem(struct kunit *test)
{
struct xe_device *xe = test->priv;
int ret;
g2g_check_skip(test);
g2g_pm_runtime_get(test);
/* Make sure to leave the system as we found it */
ret = kunit_add_action_or_reset(test, g2g_recreate_ctb, xe);
KUNIT_ASSERT_EQ_MSG(test, 0, ret, "Failed to register CTB re-creation action\n");
kunit_info(test, "Testing CTB type 'default'...\n");
g2g_reinit(test, xe, G2G_CTB_TYPE_DEFAULT, NULL);
g2g_run_test(test, xe);
kunit_info(test, "Testing CTB type 'host'...\n");
g2g_reinit(test, xe, G2G_CTB_TYPE_HOST, NULL);
g2g_run_test(test, xe);
if (IS_DGFX(xe)) {
struct xe_tile *tile;
int id;
for_each_tile(tile, xe, id) {
kunit_info(test, "Testing CTB type 'tile: #%d'...\n", id);
g2g_reinit(test, xe, G2G_CTB_TYPE_TILE, tile);
g2g_run_test(test, xe);
}
} else {
kunit_info(test, "Skipping local memory on integrated platform\n");
}
kunit_release_action(test, g2g_recreate_ctb, xe);
kunit_release_action(test, g2g_pm_runtime_put, xe);
}
static struct kunit_case xe_guc_g2g_tests[] = {
KUNIT_CASE_PARAM(xe_live_guc_g2g_kunit_default, xe_pci_live_device_gen_param),
KUNIT_CASE_PARAM(xe_live_guc_g2g_kunit_allmem, xe_pci_live_device_gen_param),
{}
};
VISIBLE_IF_KUNIT
struct kunit_suite xe_guc_g2g_test_suite = {
.name = "xe_guc_g2g",
.test_cases = xe_guc_g2g_tests,
.init = xe_kunit_helper_xe_device_live_test_init,
};
EXPORT_SYMBOL_IF_KUNIT(xe_guc_g2g_test_suite);
@@ -0,0 +1,136 @@
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2024 Intel Corporation
*/
#include <kunit/test.h>
#include "xe_device.h"
#include "xe_kunit_helpers.h"
static int guc_id_mgr_test_init(struct kunit *test)
{
struct xe_guc_id_mgr *idm;
xe_kunit_helper_xe_device_test_init(test);
idm = &xe_device_get_gt(test->priv, 0)->uc.guc.submission_state.idm;
mutex_init(idm_mutex(idm));
test->priv = idm;
return 0;
}
static void bad_init(struct kunit *test)
{
struct xe_guc_id_mgr *idm = test->priv;
KUNIT_EXPECT_EQ(test, -EINVAL, xe_guc_id_mgr_init(idm, 0));
KUNIT_EXPECT_EQ(test, -ERANGE, xe_guc_id_mgr_init(idm, GUC_ID_MAX + 1));
}
static void no_init(struct kunit *test)
{
struct xe_guc_id_mgr *idm = test->priv;
mutex_lock(idm_mutex(idm));
KUNIT_EXPECT_EQ(test, -ENODATA, xe_guc_id_mgr_reserve_locked(idm, 0));
mutex_unlock(idm_mutex(idm));
KUNIT_EXPECT_EQ(test, -ENODATA, xe_guc_id_mgr_reserve(idm, 1, 1));
}
static void init_fini(struct kunit *test)
{
struct xe_guc_id_mgr *idm = test->priv;
KUNIT_ASSERT_EQ(test, 0, xe_guc_id_mgr_init(idm, -1));
KUNIT_EXPECT_NOT_NULL(test, idm->bitmap);
KUNIT_EXPECT_EQ(test, idm->total, GUC_ID_MAX);
__fini_idm(NULL, idm);
KUNIT_EXPECT_NULL(test, idm->bitmap);
KUNIT_EXPECT_EQ(test, idm->total, 0);
}
static void check_used(struct kunit *test)
{
struct xe_guc_id_mgr *idm = test->priv;
unsigned int n;
KUNIT_ASSERT_EQ(test, 0, xe_guc_id_mgr_init(idm, 2));
mutex_lock(idm_mutex(idm));
for (n = 0; n < idm->total; n++) {
kunit_info(test, "n=%u", n);
KUNIT_EXPECT_EQ(test, idm->used, n);
KUNIT_EXPECT_GE(test, idm_reserve_chunk_locked(idm, 1, 0), 0);
KUNIT_EXPECT_EQ(test, idm->used, n + 1);
}
KUNIT_EXPECT_EQ(test, idm->used, idm->total);
idm_release_chunk_locked(idm, 0, idm->used);
KUNIT_EXPECT_EQ(test, idm->used, 0);
mutex_unlock(idm_mutex(idm));
}
static void check_quota(struct kunit *test)
{
struct xe_guc_id_mgr *idm = test->priv;
unsigned int n;
KUNIT_ASSERT_EQ(test, 0, xe_guc_id_mgr_init(idm, 2));
mutex_lock(idm_mutex(idm));
for (n = 0; n < idm->total - 1; n++) {
kunit_info(test, "n=%u", n);
KUNIT_EXPECT_EQ(test, idm_reserve_chunk_locked(idm, 1, idm->total), -EDQUOT);
KUNIT_EXPECT_EQ(test, idm_reserve_chunk_locked(idm, 1, idm->total - n), -EDQUOT);
KUNIT_EXPECT_EQ(test, idm_reserve_chunk_locked(idm, idm->total - n, 1), -EDQUOT);
KUNIT_EXPECT_GE(test, idm_reserve_chunk_locked(idm, 1, 1), 0);
}
KUNIT_EXPECT_LE(test, 0, idm_reserve_chunk_locked(idm, 1, 0));
KUNIT_EXPECT_EQ(test, idm->used, idm->total);
idm_release_chunk_locked(idm, 0, idm->total);
KUNIT_EXPECT_EQ(test, idm->used, 0);
mutex_unlock(idm_mutex(idm));
}
static void check_all(struct kunit *test)
{
struct xe_guc_id_mgr *idm = test->priv;
unsigned int n;
KUNIT_ASSERT_EQ(test, 0, xe_guc_id_mgr_init(idm, -1));
mutex_lock(idm_mutex(idm));
for (n = 0; n < idm->total; n++)
KUNIT_EXPECT_LE(test, 0, idm_reserve_chunk_locked(idm, 1, 0));
KUNIT_EXPECT_EQ(test, idm->used, idm->total);
for (n = 0; n < idm->total; n++)
idm_release_chunk_locked(idm, n, 1);
mutex_unlock(idm_mutex(idm));
}
static struct kunit_case guc_id_mgr_test_cases[] = {
KUNIT_CASE(bad_init),
KUNIT_CASE(no_init),
KUNIT_CASE(init_fini),
KUNIT_CASE(check_used),
KUNIT_CASE(check_quota),
KUNIT_CASE_SLOW(check_all),
{}
};
static struct kunit_suite guc_id_mgr_suite = {
.name = "guc_idm",
.test_cases = guc_id_mgr_test_cases,
.init = guc_id_mgr_test_init,
.exit = NULL,
};
kunit_test_suites(&guc_id_mgr_suite);
@@ -0,0 +1,522 @@
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2023 Intel Corporation
*/
#include <kunit/static_stub.h>
#include <kunit/test.h>
#include <kunit/test-bug.h>
#include "xe_device.h"
#include "xe_kunit_helpers.h"
#include "xe_pci_test.h"
#define TEST_RID 1234
#define TEST_VFID 5
#define TEST_LEN 6
#define TEST_ACTION 0xa
#define TEST_DATA(n) (0xd0 + (n))
static int replacement_relay_get_totalvfs(struct xe_guc_relay *relay)
{
return TEST_VFID;
}
static int relay_test_init(struct kunit *test)
{
struct xe_pci_fake_data fake = {
.sriov_mode = XE_SRIOV_MODE_PF,
.platform = XE_TIGERLAKE, /* some random platform */
.subplatform = XE_SUBPLATFORM_NONE,
};
struct xe_guc_relay *relay;
struct xe_device *xe;
test->priv = &fake;
xe_kunit_helper_xe_device_test_init(test);
xe = test->priv;
KUNIT_ASSERT_EQ(test, xe_sriov_init(xe), 0);
relay = &xe_device_get_gt(xe, 0)->uc.guc.relay;
kunit_activate_static_stub(test, relay_get_totalvfs,
replacement_relay_get_totalvfs);
KUNIT_ASSERT_EQ(test, xe_guc_relay_init(relay), 0);
KUNIT_EXPECT_TRUE(test, relay_is_ready(relay));
relay->last_rid = TEST_RID - 1;
test->priv = relay;
return 0;
}
static const u32 TEST_MSG[TEST_LEN] = {
FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_EVENT) |
FIELD_PREP_CONST(GUC_HXG_EVENT_MSG_0_ACTION, TEST_ACTION) |
FIELD_PREP_CONST(GUC_HXG_EVENT_MSG_0_DATA0, TEST_DATA(0)),
TEST_DATA(1), TEST_DATA(2), TEST_DATA(3), TEST_DATA(4),
};
static int replacement_xe_guc_ct_send_recv_always_fails(struct xe_guc_ct *ct,
const u32 *msg, u32 len,
u32 *response_buffer)
{
struct kunit *test = kunit_get_current_test();
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ct);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, msg);
KUNIT_ASSERT_GE(test, len, GUC_HXG_MSG_MIN_LEN);
return -ECOMM;
}
static int replacement_xe_guc_ct_send_recv_expects_pf2guc_relay(struct xe_guc_ct *ct,
const u32 *msg, u32 len,
u32 *response_buffer)
{
struct kunit *test = kunit_get_current_test();
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ct);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, msg);
KUNIT_ASSERT_GE(test, len, PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN);
KUNIT_ASSERT_EQ(test, len, PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN + TEST_LEN);
KUNIT_EXPECT_EQ(test, GUC_HXG_ORIGIN_HOST, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, msg[0]));
KUNIT_EXPECT_EQ(test, GUC_HXG_TYPE_REQUEST, FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]));
KUNIT_EXPECT_EQ(test, XE_GUC_ACTION_PF2GUC_RELAY_TO_VF,
FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0]));
KUNIT_EXPECT_EQ(test, TEST_VFID,
FIELD_GET(PF2GUC_RELAY_TO_VF_REQUEST_MSG_1_VFID, msg[1]));
KUNIT_EXPECT_EQ(test, TEST_RID,
FIELD_GET(PF2GUC_RELAY_TO_VF_REQUEST_MSG_2_RELAY_ID, msg[2]));
KUNIT_EXPECT_MEMEQ(test, TEST_MSG, msg + PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN,
sizeof(u32) * TEST_LEN);
return 0;
}
static const u32 test_guc2pf[GUC2PF_RELAY_FROM_VF_EVENT_MSG_MAX_LEN] = {
/* transport */
FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_GUC) |
FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_EVENT) |
FIELD_PREP_CONST(GUC_HXG_EVENT_MSG_0_ACTION, XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF),
FIELD_PREP_CONST(GUC2PF_RELAY_FROM_VF_EVENT_MSG_1_VFID, TEST_VFID),
FIELD_PREP_CONST(GUC2PF_RELAY_FROM_VF_EVENT_MSG_2_RELAY_ID, TEST_RID),
/* payload */
FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS),
};
static const u32 test_guc2vf[GUC2VF_RELAY_FROM_PF_EVENT_MSG_MAX_LEN] = {
/* transport */
FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_GUC) |
FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_EVENT) |
FIELD_PREP_CONST(GUC_HXG_EVENT_MSG_0_ACTION, XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF),
FIELD_PREP_CONST(GUC2VF_RELAY_FROM_PF_EVENT_MSG_1_RELAY_ID, TEST_RID),
/* payload */
FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS),
};
static void pf_rejects_guc2pf_too_short(struct kunit *test)
{
const u32 len = GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN - 1;
struct xe_guc_relay *relay = test->priv;
const u32 *msg = test_guc2pf;
KUNIT_ASSERT_EQ(test, -EPROTO, xe_guc_relay_process_guc2pf(relay, msg, len));
}
static void pf_rejects_guc2pf_too_long(struct kunit *test)
{
const u32 len = GUC2PF_RELAY_FROM_VF_EVENT_MSG_MAX_LEN + 1;
struct xe_guc_relay *relay = test->priv;
const u32 *msg = test_guc2pf;
KUNIT_ASSERT_EQ(test, -EMSGSIZE, xe_guc_relay_process_guc2pf(relay, msg, len));
}
static void pf_rejects_guc2pf_no_payload(struct kunit *test)
{
const u32 len = GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN;
struct xe_guc_relay *relay = test->priv;
const u32 *msg = test_guc2pf;
KUNIT_ASSERT_EQ(test, -EPROTO, xe_guc_relay_process_guc2pf(relay, msg, len));
}
static void pf_fails_no_payload(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
const u32 msg = 0;
KUNIT_ASSERT_EQ(test, -EPROTO, relay_process_msg(relay, TEST_VFID, TEST_RID, &msg, 0));
}
static void pf_fails_bad_origin(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
static const u32 msg[] = {
FIELD_PREP_CONST(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_GUC) |
FIELD_PREP_CONST(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_RESPONSE_SUCCESS),
};
u32 len = ARRAY_SIZE(msg);
KUNIT_ASSERT_EQ(test, -EPROTO, relay_process_msg(relay, TEST_VFID, TEST_RID, msg, len));
}
static void pf_fails_bad_type(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
const u32 msg[] = {
FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
FIELD_PREP(GUC_HXG_MSG_0_TYPE, 4), /* only 4 is undefined */
};
u32 len = ARRAY_SIZE(msg);
KUNIT_ASSERT_EQ(test, -EBADRQC, relay_process_msg(relay, TEST_VFID, TEST_RID, msg, len));
}
static void pf_txn_reports_error(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
struct relay_transaction *txn;
txn = __relay_get_transaction(relay, false, TEST_VFID, TEST_RID,
TEST_MSG, TEST_LEN, NULL, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txn);
kunit_activate_static_stub(test, xe_guc_ct_send_recv,
replacement_xe_guc_ct_send_recv_always_fails);
KUNIT_EXPECT_EQ(test, -ECOMM, relay_send_transaction(relay, txn));
relay_release_transaction(relay, txn);
}
static void pf_txn_sends_pf2guc(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
struct relay_transaction *txn;
txn = __relay_get_transaction(relay, false, TEST_VFID, TEST_RID,
TEST_MSG, TEST_LEN, NULL, 0);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, txn);
kunit_activate_static_stub(test, xe_guc_ct_send_recv,
replacement_xe_guc_ct_send_recv_expects_pf2guc_relay);
KUNIT_ASSERT_EQ(test, 0, relay_send_transaction(relay, txn));
relay_release_transaction(relay, txn);
}
static void pf_sends_pf2guc(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
kunit_activate_static_stub(test, xe_guc_ct_send_recv,
replacement_xe_guc_ct_send_recv_expects_pf2guc_relay);
KUNIT_ASSERT_EQ(test, 0,
xe_guc_relay_send_to_vf(relay, TEST_VFID,
TEST_MSG, TEST_LEN, NULL, 0));
}
static int replacement_xe_guc_ct_send_recv_loopback_relay(struct xe_guc_ct *ct,
const u32 *msg, u32 len,
u32 *response_buffer)
{
struct kunit *test = kunit_get_current_test();
struct xe_guc_relay *relay = test->priv;
u32 *reply = kunit_kzalloc(test, len * sizeof(u32), GFP_KERNEL);
int (*guc2relay)(struct xe_guc_relay *, const u32 *, u32);
u32 action;
int err;
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, ct);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, msg);
KUNIT_ASSERT_GE(test, len, GUC_HXG_MSG_MIN_LEN);
KUNIT_ASSERT_EQ(test, GUC_HXG_TYPE_REQUEST,
FIELD_GET(GUC_HXG_MSG_0_TYPE, msg[0]));
KUNIT_ASSERT_GE(test, len, GUC_HXG_REQUEST_MSG_MIN_LEN);
KUNIT_ASSERT_NOT_NULL(test, reply);
switch (FIELD_GET(GUC_HXG_REQUEST_MSG_0_ACTION, msg[0])) {
case XE_GUC_ACTION_PF2GUC_RELAY_TO_VF:
KUNIT_ASSERT_GE(test, len, PF2GUC_RELAY_TO_VF_REQUEST_MSG_MIN_LEN);
action = XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF;
guc2relay = xe_guc_relay_process_guc2pf;
break;
case XE_GUC_ACTION_VF2GUC_RELAY_TO_PF:
KUNIT_ASSERT_GE(test, len, VF2GUC_RELAY_TO_PF_REQUEST_MSG_MIN_LEN);
action = XE_GUC_ACTION_GUC2VF_RELAY_FROM_PF;
guc2relay = xe_guc_relay_process_guc2vf;
break;
default:
KUNIT_FAIL(test, "bad RELAY action %#x", msg[0]);
return -EINVAL;
}
reply[0] = FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_GUC) |
FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_EVENT) |
FIELD_PREP(GUC_HXG_EVENT_MSG_0_ACTION, action);
memcpy(reply + 1, msg + 1, sizeof(u32) * (len - 1));
err = guc2relay(relay, reply, len);
KUNIT_EXPECT_EQ(test, err, 0);
return err;
}
static void test_requires_relay_testloop(struct kunit *test)
{
/*
* The debug relay action GUC_RELAY_ACTION_VFXPF_TESTLOOP is available
* only on builds with CONFIG_DRM_XE_DEBUG_SRIOV enabled.
* See "kunit.py --kconfig_add" option if it's missing.
*/
if (!IS_ENABLED(CONFIG_DRM_XE_DEBUG_SRIOV))
kunit_skip(test, "requires %s\n", __stringify(CONFIG_DRM_XE_DEBUG_SRIOV));
}
static void pf_loopback_nop(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
u32 request[] = {
FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_NOP),
};
u32 response[GUC_HXG_RESPONSE_MSG_MIN_LEN];
int ret;
test_requires_relay_testloop(test);
kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action);
kunit_activate_static_stub(test, xe_guc_ct_send_recv,
replacement_xe_guc_ct_send_recv_loopback_relay);
ret = xe_guc_relay_send_to_vf(relay, TEST_VFID,
request, ARRAY_SIZE(request),
response, ARRAY_SIZE(response));
KUNIT_ASSERT_EQ(test, ret, GUC_HXG_RESPONSE_MSG_MIN_LEN);
KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, response[0]),
GUC_HXG_ORIGIN_HOST);
KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_MSG_0_TYPE, response[0]),
GUC_HXG_TYPE_RESPONSE_SUCCESS);
KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_RESPONSE_MSG_0_DATA0, response[0]), 0);
}
static void pf_loopback_echo(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
u32 request[] = {
FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_ECHO),
TEST_DATA(1), TEST_DATA(2), TEST_DATA(3), TEST_DATA(4),
};
u32 response[ARRAY_SIZE(request)];
unsigned int n;
int ret;
test_requires_relay_testloop(test);
kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action);
kunit_activate_static_stub(test, xe_guc_ct_send_recv,
replacement_xe_guc_ct_send_recv_loopback_relay);
ret = xe_guc_relay_send_to_vf(relay, TEST_VFID,
request, ARRAY_SIZE(request),
response, ARRAY_SIZE(response));
KUNIT_ASSERT_EQ(test, ret, ARRAY_SIZE(response));
KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_MSG_0_ORIGIN, response[0]),
GUC_HXG_ORIGIN_HOST);
KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_MSG_0_TYPE, response[0]),
GUC_HXG_TYPE_RESPONSE_SUCCESS);
KUNIT_EXPECT_EQ(test, FIELD_GET(GUC_HXG_RESPONSE_MSG_0_DATA0, response[0]),
ARRAY_SIZE(response));
for (n = GUC_HXG_RESPONSE_MSG_MIN_LEN; n < ret; n++)
KUNIT_EXPECT_EQ(test, request[n], response[n]);
}
static void pf_loopback_fail(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
u32 request[] = {
FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_FAIL),
};
u32 response[GUC_HXG_RESPONSE_MSG_MIN_LEN];
int ret;
test_requires_relay_testloop(test);
kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action);
kunit_activate_static_stub(test, xe_guc_ct_send_recv,
replacement_xe_guc_ct_send_recv_loopback_relay);
ret = xe_guc_relay_send_to_vf(relay, TEST_VFID,
request, ARRAY_SIZE(request),
response, ARRAY_SIZE(response));
KUNIT_ASSERT_EQ(test, ret, -EREMOTEIO);
}
static void pf_loopback_busy(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
u32 request[] = {
FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_BUSY),
TEST_DATA(0xb),
};
u32 response[GUC_HXG_RESPONSE_MSG_MIN_LEN];
int ret;
test_requires_relay_testloop(test);
kunit_activate_static_stub(test, relay_testonly_nop, relay_process_incoming_action);
kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action);
kunit_activate_static_stub(test, xe_guc_ct_send_recv,
replacement_xe_guc_ct_send_recv_loopback_relay);
ret = xe_guc_relay_send_to_vf(relay, TEST_VFID,
request, ARRAY_SIZE(request),
response, ARRAY_SIZE(response));
KUNIT_ASSERT_EQ(test, ret, GUC_HXG_RESPONSE_MSG_MIN_LEN);
}
static void pf_loopback_retry(struct kunit *test)
{
struct xe_guc_relay *relay = test->priv;
u32 request[] = {
FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) |
FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_RELAY_ACTION_VFXPF_TESTLOOP) |
FIELD_PREP(GUC_HXG_REQUEST_MSG_0_DATA0, VFXPF_TESTLOOP_OPCODE_RETRY),
TEST_DATA(0xd), TEST_DATA(0xd),
};
u32 response[GUC_HXG_RESPONSE_MSG_MIN_LEN];
int ret;
test_requires_relay_testloop(test);
kunit_activate_static_stub(test, relay_kick_worker, relay_process_incoming_action);
kunit_activate_static_stub(test, xe_guc_ct_send_recv,
replacement_xe_guc_ct_send_recv_loopback_relay);
ret = xe_guc_relay_send_to_vf(relay, TEST_VFID,
request, ARRAY_SIZE(request),
response, ARRAY_SIZE(response));
KUNIT_ASSERT_EQ(test, ret, GUC_HXG_RESPONSE_MSG_MIN_LEN);
}
static struct kunit_case pf_relay_test_cases[] = {
KUNIT_CASE(pf_rejects_guc2pf_too_short),
KUNIT_CASE(pf_rejects_guc2pf_too_long),
KUNIT_CASE(pf_rejects_guc2pf_no_payload),
KUNIT_CASE(pf_fails_no_payload),
KUNIT_CASE(pf_fails_bad_origin),
KUNIT_CASE(pf_fails_bad_type),
KUNIT_CASE(pf_txn_reports_error),
KUNIT_CASE(pf_txn_sends_pf2guc),
KUNIT_CASE(pf_sends_pf2guc),
KUNIT_CASE(pf_loopback_nop),
KUNIT_CASE(pf_loopback_echo),
KUNIT_CASE(pf_loopback_fail),
KUNIT_CASE_SLOW(pf_loopback_busy),
KUNIT_CASE_SLOW(pf_loopback_retry),
{}
};
static struct kunit_suite pf_relay_suite = {
.name = "pf_relay",
.test_cases = pf_relay_test_cases,
.init = relay_test_init,
};
static void vf_rejects_guc2vf_too_short(struct kunit *test)
{
const u32 len = GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN - 1;
struct xe_guc_relay *relay = test->priv;
const u32 *msg = test_guc2vf;
KUNIT_ASSERT_EQ(test, -EPROTO, xe_guc_relay_process_guc2vf(relay, msg, len));
}
static void vf_rejects_guc2vf_too_long(struct kunit *test)
{
const u32 len = GUC2VF_RELAY_FROM_PF_EVENT_MSG_MAX_LEN + 1;
struct xe_guc_relay *relay = test->priv;
const u32 *msg = test_guc2vf;
KUNIT_ASSERT_EQ(test, -EMSGSIZE, xe_guc_relay_process_guc2vf(relay, msg, len));
}
static void vf_rejects_guc2vf_no_payload(struct kunit *test)
{
const u32 len = GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN;
struct xe_guc_relay *relay = test->priv;
const u32 *msg = test_guc2vf;
KUNIT_ASSERT_EQ(test, -EPROTO, xe_guc_relay_process_guc2vf(relay, msg, len));
}
static struct kunit_case vf_relay_test_cases[] = {
KUNIT_CASE(vf_rejects_guc2vf_too_short),
KUNIT_CASE(vf_rejects_guc2vf_too_long),
KUNIT_CASE(vf_rejects_guc2vf_no_payload),
{}
};
static struct kunit_suite vf_relay_suite = {
.name = "vf_relay",
.test_cases = vf_relay_test_cases,
.init = relay_test_init,
};
static void xe_drops_guc2pf_if_not_ready(struct kunit *test)
{
struct xe_device *xe = test->priv;
struct xe_guc_relay *relay = &xe_device_get_gt(xe, 0)->uc.guc.relay;
const u32 *msg = test_guc2pf;
u32 len = GUC2PF_RELAY_FROM_VF_EVENT_MSG_MIN_LEN + GUC_RELAY_MSG_MIN_LEN;
KUNIT_ASSERT_EQ(test, -ENODEV, xe_guc_relay_process_guc2pf(relay, msg, len));
}
static void xe_drops_guc2vf_if_not_ready(struct kunit *test)
{
struct xe_device *xe = test->priv;
struct xe_guc_relay *relay = &xe_device_get_gt(xe, 0)->uc.guc.relay;
const u32 *msg = test_guc2vf;
u32 len = GUC2VF_RELAY_FROM_PF_EVENT_MSG_MIN_LEN + GUC_RELAY_MSG_MIN_LEN;
KUNIT_ASSERT_EQ(test, -ENODEV, xe_guc_relay_process_guc2vf(relay, msg, len));
}
static void xe_rejects_send_if_not_ready(struct kunit *test)
{
struct xe_device *xe = test->priv;
struct xe_guc_relay *relay = &xe_device_get_gt(xe, 0)->uc.guc.relay;
u32 msg[GUC_RELAY_MSG_MIN_LEN];
u32 len = ARRAY_SIZE(msg);
KUNIT_ASSERT_EQ(test, -ENODEV, xe_guc_relay_send_to_pf(relay, msg, len, NULL, 0));
KUNIT_ASSERT_EQ(test, -ENODEV, relay_send_to(relay, TEST_VFID, msg, len, NULL, 0));
}
static struct kunit_case no_relay_test_cases[] = {
KUNIT_CASE(xe_drops_guc2pf_if_not_ready),
KUNIT_CASE(xe_drops_guc2vf_if_not_ready),
KUNIT_CASE(xe_rejects_send_if_not_ready),
{}
};
static struct kunit_suite no_relay_suite = {
.name = "no_relay",
.test_cases = no_relay_test_cases,
.init = xe_kunit_helper_xe_device_test_init,
};
kunit_test_suites(&no_relay_suite,
&pf_relay_suite,
&vf_relay_suite);
@@ -0,0 +1,129 @@
// SPDX-License-Identifier: GPL-2.0 AND MIT
/*
* Copyright © 2023 Intel Corporation
*/
#include <kunit/test.h>
#include <kunit/static_stub.h>
#include <kunit/visibility.h>
#include <drm/drm_drv.h>
#include <drm/drm_kunit_helpers.h>
#include "tests/xe_kunit_helpers.h"
#include "tests/xe_pci_test.h"
#include "xe_device.h"
#include "xe_device_types.h"
#include "xe_pm.h"
/**
* xe_kunit_helper_alloc_xe_device - Allocate a &xe_device for a KUnit test.
* @test: the &kunit where this &xe_device will be used
* @dev: The parent device object
*
* This function allocates xe_device using drm_kunit_helper_alloc_device().
* The xe_device allocation is managed by the test.
*
* @dev should be allocated using drm_kunit_helper_alloc_device().
*
* This function uses KUNIT_ASSERT to detect any allocation failures.
*
* Return: A pointer to the new &xe_device.
*/
struct xe_device *xe_kunit_helper_alloc_xe_device(struct kunit *test,
struct device *dev)
{
struct xe_device *xe;
xe = drm_kunit_helper_alloc_drm_device(test, dev,
struct xe_device,
drm, DRIVER_GEM);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
return xe;
}
EXPORT_SYMBOL_IF_KUNIT(xe_kunit_helper_alloc_xe_device);
static void kunit_action_restore_priv(void *priv)
{
struct kunit *test = kunit_get_current_test();
test->priv = priv;
}
/**
* xe_kunit_helper_xe_device_test_init - Prepare a &xe_device for a KUnit test.
* @test: the &kunit where this fake &xe_device will be used
*
* This function allocates and initializes a fake &xe_device and stores its
* pointer as &kunit.priv to allow the test code to access it.
*
* This function can be directly used as custom implementation of
* &kunit_suite.init.
*
* It is possible to prepare specific variant of the fake &xe_device by passing
* in &kunit.priv pointer to the struct xe_pci_fake_data supplemented with
* desired parameters prior to calling this function.
*
* This function uses KUNIT_ASSERT to detect any failures.
*
* Return: Always 0.
*/
int xe_kunit_helper_xe_device_test_init(struct kunit *test)
{
struct xe_device *xe;
struct device *dev;
int err;
dev = drm_kunit_helper_alloc_device(test);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, dev);
xe = xe_kunit_helper_alloc_xe_device(test, dev);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
err = xe_pci_fake_device_init(xe);
KUNIT_ASSERT_EQ(test, err, 0);
err = kunit_add_action_or_reset(test, kunit_action_restore_priv, test->priv);
KUNIT_ASSERT_EQ(test, err, 0);
test->priv = xe;
return 0;
}
EXPORT_SYMBOL_IF_KUNIT(xe_kunit_helper_xe_device_test_init);
KUNIT_DEFINE_ACTION_WRAPPER(put_xe_pm_runtime, xe_pm_runtime_put, struct xe_device *);
/**
* xe_kunit_helper_xe_device_live_test_init - Prepare a &xe_device for
* use in a live KUnit test.
* @test: the &kunit where live &xe_device will be used
*
* This function expects pointer to the &xe_device in the &test.param_value,
* like it is prepared by the &xe_pci_live_device_gen_param and stores that
* pointer as &kunit.priv to allow the test code to access it.
*
* This function makes sure that device is not wedged and then resumes it
* to avoid waking up the device inside the test. It uses deferred cleanup
* action to release a runtime_pm reference.
*
* This function can be used as custom implementation of &kunit_suite.init.
*
* This function uses KUNIT_ASSERT to detect any failures.
*
* Return: Always 0.
*/
int xe_kunit_helper_xe_device_live_test_init(struct kunit *test)
{
struct xe_device *xe = xe_device_const_cast(test->param_value);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, xe);
kunit_info(test, "running on %s device\n", xe->info.platform_name);
KUNIT_ASSERT_FALSE(test, xe_device_wedged(xe));
xe_pm_runtime_get(xe);
KUNIT_ASSERT_EQ(test, 0, kunit_add_action_or_reset(test, put_xe_pm_runtime, xe));
test->priv = xe;
return 0;
}
EXPORT_SYMBOL_IF_KUNIT(xe_kunit_helper_xe_device_live_test_init);
@@ -0,0 +1,19 @@
/* SPDX-License-Identifier: GPL-2.0 AND MIT */
/*
* Copyright © 2023 Intel Corporation
*/
#ifndef _XE_KUNIT_HELPERS_H_
#define _XE_KUNIT_HELPERS_H_
struct device;
struct kunit;
struct xe_device;
struct xe_device *xe_kunit_helper_alloc_xe_device(struct kunit *test,
struct device *dev);
int xe_kunit_helper_xe_device_test_init(struct kunit *test);
int xe_kunit_helper_xe_device_live_test_init(struct kunit *test);
#endif
@@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Copyright © 2023 Intel Corporation
*/
#include <linux/module.h>
#include <kunit/test.h>
extern struct kunit_suite xe_bo_test_suite;
extern struct kunit_suite xe_bo_shrink_test_suite;
extern struct kunit_suite xe_dma_buf_test_suite;
extern struct kunit_suite xe_migrate_test_suite;
extern struct kunit_suite xe_mocs_test_suite;
extern struct kunit_suite xe_guc_g2g_test_suite;
kunit_test_suite(xe_bo_test_suite);
kunit_test_suite(xe_bo_shrink_test_suite);
kunit_test_suite(xe_dma_buf_test_suite);
kunit_test_suite(xe_migrate_test_suite);
kunit_test_suite(xe_mocs_test_suite);
kunit_test_suite(xe_guc_g2g_test_suite);
MODULE_AUTHOR("Intel Corporation");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("xe live kunit tests");
MODULE_IMPORT_NS("EXPORTED_FOR_KUNIT_TESTING");

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