On 14.10.2022 16:02, Matt Roper wrote: > Xe_HP has some MCR registers that need to be polled for completion of > operations like TLB invalidation. Those registers are in the GAM range, > which rolls up the status from each unit into the 'primary' instance's > value. This makes it useful to have a dedicated 'wait for register' > function that handles this on MCR registers, similar to the > __intel_wait_for_register_fw() function we already have for regular > registers. > > Signed-off-by: Matt Roper <matthew.d.roper@xxxxxxxxx> > --- > drivers/gpu/drm/i915/gt/intel_gt_mcr.c | 55 ++++++++++++++++++++++++++ > drivers/gpu/drm/i915/gt/intel_gt_mcr.h | 7 ++++ > 2 files changed, 62 insertions(+) Reviewed-by: Balasubramani Vivekanandan <balasubramani.vivekanandan@xxxxxxxxx> Regards, Bala > > diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c > index 4dc360f4e344..1ed9bc4dccfd 100644 > --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.c > +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.c > @@ -568,3 +568,58 @@ void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss, > return; > } > } > + > +/** > + * intel_gt_mcr_wait_for_reg_fw - wait until MCR register matches expected state > + * @gt: GT structure > + * @reg: the register to read > + * @mask: mask to apply to register value > + * @value: value to wait for > + * @fast_timeout_us: fast timeout in microsecond for atomic/tight wait > + * @slow_timeout_ms: slow timeout in millisecond > + * > + * This routine waits until the target register @reg contains the expected > + * @value after applying the @mask, i.e. it waits until :: > + * > + * (intel_gt_mcr_read_any_fw(gt, reg) & mask) == value > + * > + * Otherwise, the wait will timeout after @slow_timeout_ms milliseconds. > + * For atomic context @slow_timeout_ms must be zero and @fast_timeout_us > + * must be not larger than 20,0000 microseconds. > + * > + * This function is basically an MCR-friendly version of > + * __intel_wait_for_register_fw(). Generally this function will only be used > + * on GAM registers which are a bit special --- although they're MCR registers, > + * reads (e.g., waiting for status updates) are always directed to the primary > + * instance. > + * > + * Note that this routine assumes the caller holds forcewake asserted, it is > + * not suitable for very long waits. > + * > + * Return: 0 if the register matches the desired condition, or -ETIMEDOUT. > + */ > +int intel_gt_mcr_wait_for_reg_fw(struct intel_gt *gt, > + i915_reg_t reg, > + u32 mask, > + u32 value, > + unsigned int fast_timeout_us, > + unsigned int slow_timeout_ms) > +{ > + u32 reg_value = 0; > +#define done (((reg_value = intel_gt_mcr_read_any_fw(gt, reg)) & mask) == value) > + int ret; > + > + /* Catch any overuse of this function */ > + might_sleep_if(slow_timeout_ms); > + GEM_BUG_ON(fast_timeout_us > 20000); > + GEM_BUG_ON(!fast_timeout_us && !slow_timeout_ms); > + > + ret = -ETIMEDOUT; > + if (fast_timeout_us && fast_timeout_us <= 20000) > + ret = _wait_for_atomic(done, fast_timeout_us, 0); > + if (ret && slow_timeout_ms) > + ret = wait_for(done, slow_timeout_ms); > + > + return ret; > +#undef done > +} > diff --git a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h > index 781b267478db..548f922cd9fa 100644 > --- a/drivers/gpu/drm/i915/gt/intel_gt_mcr.h > +++ b/drivers/gpu/drm/i915/gt/intel_gt_mcr.h > @@ -37,6 +37,13 @@ void intel_gt_mcr_report_steering(struct drm_printer *p, struct intel_gt *gt, > void intel_gt_mcr_get_ss_steering(struct intel_gt *gt, unsigned int dss, > unsigned int *group, unsigned int *instance); > > +int intel_gt_mcr_wait_for_reg_fw(struct intel_gt *gt, > + i915_reg_t reg, > + u32 mask, > + u32 value, > + unsigned int fast_timeout_us, > + unsigned int slow_timeout_ms); > + > /* > * Helper for for_each_ss_steering loop. On pre-Xe_HP platforms, subslice > * presence is determined by using the group/instance as direct lookups in the > -- > 2.37.3 >