// SPDX-License-Identifier: MIT /* * Copyright © 2022 Intel Corporation */ #include "xe_gt_mcr.h" #include "regs/xe_gt_regs.h" #include "xe_assert.h" #include "xe_gt.h" #include "xe_gt_topology.h" #include "xe_gt_types.h" #include "xe_mmio.h" #include "xe_sriov.h" /** * DOC: GT Multicast/Replicated (MCR) Register Support * * Some GT registers are designed as "multicast" or "replicated" registers: * multiple instances of the same register share a single MMIO offset. MCR * registers are generally used when the hardware needs to potentially track * independent values of a register per hardware unit (e.g., per-subslice, * per-L3bank, etc.). The specific types of replication that exist vary * per-platform. * * MMIO accesses to MCR registers are controlled according to the settings * programmed in the platform's MCR_SELECTOR register(s). MMIO writes to MCR * registers can be done in either multicast (a single write updates all * instances of the register to the same value) or unicast (a write updates only * one specific instance) form. Reads of MCR registers always operate in a * unicast manner regardless of how the multicast/unicast bit is set in * MCR_SELECTOR. Selection of a specific MCR instance for unicast operations is * referred to as "steering." * * If MCR register operations are steered toward a hardware unit that is * fused off or currently powered down due to power gating, the MMIO operation * is "terminated" by the hardware. Terminated read operations will return a * value of zero and terminated unicast write operations will be silently * ignored. During device initialization, the goal of the various * ``init_steering_*()`` functions is to apply the platform-specific rules for * each MCR register type to identify a steering target that will select a * non-terminated instance. * * MCR registers are not available on Virtual Function (VF). */ #define STEER_SEMAPHORE … static inline struct xe_reg to_xe_reg(struct xe_reg_mcr reg_mcr) { … } enum { … }; static const struct xe_mmio_range xelp_l3bank_steering_table[] = …; static const struct xe_mmio_range xehp_l3bank_steering_table[] = …; /* * Although the bspec lists more "MSLICE" ranges than shown here, some of those * are of a "GAM" subclass that has special rules and doesn't need to be * included here. */ static const struct xe_mmio_range xehp_mslice_steering_table[] = …; static const struct xe_mmio_range xehp_lncf_steering_table[] = …; /* * We have several types of MCR registers where steering to (0,0) will always * provide us with a non-terminated value. We'll stick them all in the same * table for simplicity. */ static const struct xe_mmio_range xehpc_instance0_steering_table[] = …; static const struct xe_mmio_range xelpg_instance0_steering_table[] = …; static const struct xe_mmio_range xelpg_l3bank_steering_table[] = …; static const struct xe_mmio_range xelp_dss_steering_table[] = …; /* DSS steering is used for GSLICE ranges as well */ static const struct xe_mmio_range xehp_dss_steering_table[] = …; /* DSS steering is used for COMPUTE ranges as well */ static const struct xe_mmio_range xehpc_dss_steering_table[] = …; /* DSS steering is used for SLICE ranges as well */ static const struct xe_mmio_range xelpg_dss_steering_table[] = …; static const struct xe_mmio_range xelpmp_oaddrm_steering_table[] = …; static const struct xe_mmio_range dg2_implicit_steering_table[] = …; static const struct xe_mmio_range xe2lpg_dss_steering_table[] = …; static const struct xe_mmio_range xe2lpg_sqidi_psmi_steering_table[] = …; static const struct xe_mmio_range xe2lpg_instance0_steering_table[] = …; static const struct xe_mmio_range xe2lpm_gpmxmt_steering_table[] = …; static const struct xe_mmio_range xe2lpm_instance0_steering_table[] = …; static void init_steering_l3bank(struct xe_gt *gt) { … } static void init_steering_mslice(struct xe_gt *gt) { … } static unsigned int dss_per_group(struct xe_gt *gt) { … } /** * xe_gt_mcr_get_dss_steering - Get the group/instance steering for a DSS * @gt: GT structure * @dss: DSS ID to obtain steering for * @group: pointer to storage for steering group ID * @instance: pointer to storage for steering instance ID */ void xe_gt_mcr_get_dss_steering(struct xe_gt *gt, unsigned int dss, u16 *group, u16 *instance) { … } static void init_steering_dss(struct xe_gt *gt) { … } static void init_steering_oaddrm(struct xe_gt *gt) { … } static void init_steering_sqidi_psmi(struct xe_gt *gt) { … } static void init_steering_inst0(struct xe_gt *gt) { … } static const struct { … } xe_steering_types[] = …; /** * xe_gt_mcr_init_early - Early initialization of the MCR support * @gt: GT structure * * Perform early software only initialization of the MCR lock to allow * the synchronization on accessing the STEER_SEMAPHORE register and * use the xe_gt_mcr_multicast_write() function. */ void xe_gt_mcr_init_early(struct xe_gt *gt) { … } /** * xe_gt_mcr_init - Normal initialization of the MCR support * @gt: GT structure * * Perform normal initialization of the MCR for all usages. */ void xe_gt_mcr_init(struct xe_gt *gt) { … } /** * xe_gt_mcr_set_implicit_defaults - Initialize steer control registers * @gt: GT structure * * Some register ranges don't need to have their steering control registers * changed on each access - it's sufficient to set them once on initialization. * This function sets those registers for each platform * */ void xe_gt_mcr_set_implicit_defaults(struct xe_gt *gt) { … } /* * xe_gt_mcr_get_nonterminated_steering - find group/instance values that * will steer a register to a non-terminated instance * @gt: GT structure * @reg: register for which the steering is required * @group: return variable for group steering * @instance: return variable for instance steering * * This function returns a group/instance pair that is guaranteed to work for * read steering of the given register. Note that a value will be returned even * if the register is not replicated and therefore does not actually require * steering. * * Returns true if the caller should steer to the @group/@instance values * returned. Returns false if the caller need not perform any steering */ static bool xe_gt_mcr_get_nonterminated_steering(struct xe_gt *gt, struct xe_reg_mcr reg_mcr, u8 *group, u8 *instance) { … } /* * Obtain exclusive access to MCR steering. On MTL and beyond we also need * to synchronize with external clients (e.g., firmware), so a semaphore * register will also need to be taken. */ static void mcr_lock(struct xe_gt *gt) __acquires(>->mcr_lock) { … } static void mcr_unlock(struct xe_gt *gt) __releases(>->mcr_lock) { … } /* * Access a register with specific MCR steering * * Caller needs to make sure the relevant forcewake wells are up. */ static u32 rw_with_mcr_steering(struct xe_gt *gt, struct xe_reg_mcr reg_mcr, u8 rw_flag, int group, int instance, u32 value) { … } /** * xe_gt_mcr_unicast_read_any - reads a non-terminated instance of an MCR register * @gt: GT structure * @reg_mcr: register to read * * Reads a GT MCR register. The read will be steered to a non-terminated * instance (i.e., one that isn't fused off or powered down by power gating). * This function assumes the caller is already holding any necessary forcewake * domains. * * Returns the value from a non-terminated instance of @reg. */ u32 xe_gt_mcr_unicast_read_any(struct xe_gt *gt, struct xe_reg_mcr reg_mcr) { … } /** * xe_gt_mcr_unicast_read - read a specific instance of an MCR register * @gt: GT structure * @reg_mcr: the MCR register to read * @group: the MCR group * @instance: the MCR instance * * Returns the value read from an MCR register after steering toward a specific * group/instance. */ u32 xe_gt_mcr_unicast_read(struct xe_gt *gt, struct xe_reg_mcr reg_mcr, int group, int instance) { … } /** * xe_gt_mcr_unicast_write - write a specific instance of an MCR register * @gt: GT structure * @reg_mcr: the MCR register to write * @value: value to write * @group: the MCR group * @instance: the MCR instance * * Write an MCR register in unicast mode after steering toward a specific * group/instance. */ void xe_gt_mcr_unicast_write(struct xe_gt *gt, struct xe_reg_mcr reg_mcr, u32 value, int group, int instance) { … } /** * xe_gt_mcr_multicast_write - write a value to all instances of an MCR register * @gt: GT structure * @reg_mcr: the MCR register to write * @value: value to write * * Write an MCR register in multicast mode to update all instances. */ void xe_gt_mcr_multicast_write(struct xe_gt *gt, struct xe_reg_mcr reg_mcr, u32 value) { … } void xe_gt_mcr_steering_dump(struct xe_gt *gt, struct drm_printer *p) { … }