[Intel-gfx] [PATCH 5/6] drm/i915: dynamically allocate forcewake domains
Tvrtko Ursulin
tvrtko.ursulin at linux.intel.com
Tue Jun 18 09:23:13 UTC 2019
On 17/06/2019 19:09, Daniele Ceraolo Spurio wrote:
> We'd like to introduce a display uncore with no forcewake domains, so
> let's avoid wasting memory and be ready to allocate only what we need.
> Even without multiple uncore, we still don't need all the domains on all
> gens.
Looks good in principle, only a few conversation points below.
>
> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
> ---
> drivers/gpu/drm/i915/intel_uncore.c | 155 ++++++++++++++++++----------
> drivers/gpu/drm/i915/intel_uncore.h | 13 +--
> 2 files changed, 102 insertions(+), 66 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
> index c0f5567ee096..7f311827c3ef 100644
> --- a/drivers/gpu/drm/i915/intel_uncore.c
> +++ b/drivers/gpu/drm/i915/intel_uncore.c
> @@ -344,7 +344,7 @@ intel_uncore_fw_release_timer(struct hrtimer *timer)
> {
> struct intel_uncore_forcewake_domain *domain =
> container_of(timer, struct intel_uncore_forcewake_domain, timer);
> - struct intel_uncore *uncore = forcewake_domain_to_uncore(domain);
> + struct intel_uncore *uncore = domain->uncore;
> unsigned long irqflags;
>
> assert_rpm_device_not_suspended(uncore->rpm);
> @@ -1291,23 +1291,23 @@ do { \
> (uncore)->funcs.read_fw_domains = x##_reg_read_fw_domains; \
> } while (0)
>
> -static void fw_domain_init(struct intel_uncore *uncore,
> +static int fw_domain_init(struct intel_uncore *uncore,
> enum forcewake_domain_id domain_id,
> i915_reg_t reg_set,
> i915_reg_t reg_ack)
> {
> struct intel_uncore_forcewake_domain *d;
>
> - if (WARN_ON(domain_id >= FW_DOMAIN_ID_COUNT))
> - return;
> -
> - d = &uncore->fw_domain[domain_id];
> + GEM_BUG_ON(domain_id >= FW_DOMAIN_ID_COUNT);
>
> - WARN_ON(d->wake_count);
I wonder what was this for.
Do you want to add some protection against double init of the same domain?
> + d = kzalloc(sizeof(*d), GFP_KERNEL);
> + if (!d)
> + return -ENOMEM;
>
> WARN_ON(!i915_mmio_reg_valid(reg_set));
> WARN_ON(!i915_mmio_reg_valid(reg_ack));
>
> + d->uncore = uncore;
> d->wake_count = 0;
> d->reg_set = uncore->regs + i915_mmio_reg_offset(reg_set);
> d->reg_ack = uncore->regs + i915_mmio_reg_offset(reg_ack);
> @@ -1324,7 +1324,6 @@ static void fw_domain_init(struct intel_uncore *uncore,
> BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX0 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX0));
> BUILD_BUG_ON(FORCEWAKE_MEDIA_VEBOX1 != (1 << FW_DOMAIN_ID_MEDIA_VEBOX1));
>
> -
> d->mask = BIT(domain_id);
>
> hrtimer_init(&d->timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
> @@ -1333,6 +1332,10 @@ static void fw_domain_init(struct intel_uncore *uncore,
> uncore->fw_domains |= BIT(domain_id);
>
> fw_domain_reset(d);
> +
> + uncore->fw_domain[domain_id] = d;
> +
> + return 0;
> }
>
> static void fw_domain_fini(struct intel_uncore *uncore,
> @@ -1340,77 +1343,92 @@ static void fw_domain_fini(struct intel_uncore *uncore,
> {
> struct intel_uncore_forcewake_domain *d;
>
> - if (WARN_ON(domain_id >= FW_DOMAIN_ID_COUNT))
> - return;
> + GEM_BUG_ON(domain_id >= FW_DOMAIN_ID_COUNT);
>
> - d = &uncore->fw_domain[domain_id];
> + d = fetch_and_zero(&uncore->fw_domain[domain_id]);
Maybe early if !d here and function flow just carries on?
> + uncore->fw_domains &= ~BIT(domain_id);
>
> - WARN_ON(d->wake_count);
> - WARN_ON(hrtimer_cancel(&d->timer));
> - memset(d, 0, sizeof(*d));
> + if (d) {
> + WARN_ON(d->wake_count);
> + WARN_ON(hrtimer_cancel(&d->timer));
> + kfree(d);
> + }
> +}
>
> - uncore->fw_domains &= ~BIT(domain_id);
> +static void intel_uncore_fw_domains_fini(struct intel_uncore *uncore)
> +{
> + struct intel_uncore_forcewake_domain *d;
> + int tmp;
> +
> + for_each_fw_domain(d, uncore, tmp)
> + fw_domain_fini(uncore, d->id);
> }
>
> -static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
> +static int intel_uncore_fw_domains_init(struct intel_uncore *uncore)
> {
> struct drm_i915_private *i915 = uncore->i915;
> + int ret;
>
> GEM_BUG_ON(!intel_uncore_has_forcewake(uncore));
>
> +#define __fw_domain_init(id__, set__, ack__) \
> + ret = fw_domain_init(uncore, (id__), (set__), (ack__)); \
> + if (ret) \
> + goto out_clean;
Hidden control flow is slightly objectionable but I don't offer any nice
alternatives so I guess will have to pass. Or maybe accumulate the error
(err |= fw_domain_init(..)) as you go and then cleanup at the end if any
failed?
On the other hand the idea slightly conflicts with my other suggestion
to rename existing fw_domain_init to __fw_domain_init and call the macro
fw_domain_init and avoid all the churn below.
> +
> if (INTEL_GEN(i915) >= 11) {
> int i;
>
> - uncore->funcs.force_wake_get =
> - fw_domains_get_with_fallback;
> + uncore->funcs.force_wake_get = fw_domains_get_with_fallback;
> uncore->funcs.force_wake_put = fw_domains_put;
> - fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
> - FORCEWAKE_RENDER_GEN9,
> - FORCEWAKE_ACK_RENDER_GEN9);
> - fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER,
> - FORCEWAKE_BLITTER_GEN9,
> - FORCEWAKE_ACK_BLITTER_GEN9);
> + __fw_domain_init(FW_DOMAIN_ID_RENDER,
> + FORCEWAKE_RENDER_GEN9,
> + FORCEWAKE_ACK_RENDER_GEN9);
> + __fw_domain_init(FW_DOMAIN_ID_BLITTER,
> + FORCEWAKE_BLITTER_GEN9,
> + FORCEWAKE_ACK_BLITTER_GEN9);
> +
> for (i = 0; i < I915_MAX_VCS; i++) {
> if (!HAS_ENGINE(i915, _VCS(i)))
> continue;
>
> - fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA_VDBOX0 + i,
> - FORCEWAKE_MEDIA_VDBOX_GEN11(i),
> - FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(i));
> + __fw_domain_init(FW_DOMAIN_ID_MEDIA_VDBOX0 + i,
> + FORCEWAKE_MEDIA_VDBOX_GEN11(i),
> + FORCEWAKE_ACK_MEDIA_VDBOX_GEN11(i));
> }
> for (i = 0; i < I915_MAX_VECS; i++) {
> if (!HAS_ENGINE(i915, _VECS(i)))
> continue;
>
> - fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA_VEBOX0 + i,
> - FORCEWAKE_MEDIA_VEBOX_GEN11(i),
> - FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i));
> + __fw_domain_init(FW_DOMAIN_ID_MEDIA_VEBOX0 + i,
> + FORCEWAKE_MEDIA_VEBOX_GEN11(i),
> + FORCEWAKE_ACK_MEDIA_VEBOX_GEN11(i));
> }
> } else if (IS_GEN_RANGE(i915, 9, 10)) {
> - uncore->funcs.force_wake_get =
> - fw_domains_get_with_fallback;
> + uncore->funcs.force_wake_get = fw_domains_get_with_fallback;
> uncore->funcs.force_wake_put = fw_domains_put;
> - fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
> - FORCEWAKE_RENDER_GEN9,
> - FORCEWAKE_ACK_RENDER_GEN9);
> - fw_domain_init(uncore, FW_DOMAIN_ID_BLITTER,
> - FORCEWAKE_BLITTER_GEN9,
> - FORCEWAKE_ACK_BLITTER_GEN9);
> - fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA,
> - FORCEWAKE_MEDIA_GEN9, FORCEWAKE_ACK_MEDIA_GEN9);
> + __fw_domain_init(FW_DOMAIN_ID_RENDER,
> + FORCEWAKE_RENDER_GEN9,
> + FORCEWAKE_ACK_RENDER_GEN9);
> + __fw_domain_init(FW_DOMAIN_ID_BLITTER,
> + FORCEWAKE_BLITTER_GEN9,
> + FORCEWAKE_ACK_BLITTER_GEN9);
> + __fw_domain_init(FW_DOMAIN_ID_MEDIA,
> + FORCEWAKE_MEDIA_GEN9,
> + FORCEWAKE_ACK_MEDIA_GEN9);
> } else if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
> uncore->funcs.force_wake_get = fw_domains_get;
> uncore->funcs.force_wake_put = fw_domains_put;
> - fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
> - FORCEWAKE_VLV, FORCEWAKE_ACK_VLV);
> - fw_domain_init(uncore, FW_DOMAIN_ID_MEDIA,
> - FORCEWAKE_MEDIA_VLV, FORCEWAKE_ACK_MEDIA_VLV);
> + __fw_domain_init(FW_DOMAIN_ID_RENDER,
> + FORCEWAKE_VLV, FORCEWAKE_ACK_VLV);
> + __fw_domain_init(FW_DOMAIN_ID_MEDIA,
> + FORCEWAKE_MEDIA_VLV, FORCEWAKE_ACK_MEDIA_VLV);
> } else if (IS_HASWELL(i915) || IS_BROADWELL(i915)) {
> uncore->funcs.force_wake_get =
> fw_domains_get_with_thread_status;
> uncore->funcs.force_wake_put = fw_domains_put;
> - fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
> - FORCEWAKE_MT, FORCEWAKE_ACK_HSW);
> + __fw_domain_init(FW_DOMAIN_ID_RENDER,
> + FORCEWAKE_MT, FORCEWAKE_ACK_HSW);
> } else if (IS_IVYBRIDGE(i915)) {
> u32 ecobus;
>
> @@ -1437,8 +1455,8 @@ static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
> __raw_uncore_write32(uncore, FORCEWAKE, 0);
> __raw_posting_read(uncore, ECOBUS);
>
> - fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
> - FORCEWAKE_MT, FORCEWAKE_MT_ACK);
> + __fw_domain_init(FW_DOMAIN_ID_RENDER,
> + FORCEWAKE_MT, FORCEWAKE_MT_ACK);
>
> spin_lock_irq(&uncore->lock);
> fw_domains_get_with_thread_status(uncore, FORCEWAKE_RENDER);
> @@ -1449,19 +1467,27 @@ static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
> if (!(ecobus & FORCEWAKE_MT_ENABLE)) {
> DRM_INFO("No MT forcewake available on Ivybridge, this can result in issues\n");
> DRM_INFO("when using vblank-synced partial screen updates.\n");
> - fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
> - FORCEWAKE, FORCEWAKE_ACK);
> + __fw_domain_init(FW_DOMAIN_ID_RENDER,
> + FORCEWAKE, FORCEWAKE_ACK);
> }
> } else if (IS_GEN(i915, 6)) {
> uncore->funcs.force_wake_get =
> fw_domains_get_with_thread_status;
> uncore->funcs.force_wake_put = fw_domains_put;
> - fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
> - FORCEWAKE, FORCEWAKE_ACK);
> + __fw_domain_init(FW_DOMAIN_ID_RENDER,
> + FORCEWAKE, FORCEWAKE_ACK);
> }
>
> +#undef __fw_domain_init
> +
> /* All future platforms are expected to require complex power gating */
> WARN_ON(uncore->fw_domains == 0);
> +
> + return 0;
> +
> +out_clean:
> + intel_uncore_fw_domains_fini(uncore);
> + return ret;
> }
>
> #define ASSIGN_FW_DOMAINS_TABLE(uncore, d) \
> @@ -1562,13 +1588,17 @@ static void uncore_raw_init(struct intel_uncore *uncore)
> }
> }
>
> -static void uncore_forcewake_init(struct intel_uncore *uncore)
> +static int uncore_forcewake_init(struct intel_uncore *uncore)
> {
> struct drm_i915_private *i915 = uncore->i915;
> + int ret;
>
> GEM_BUG_ON(!intel_uncore_has_forcewake(uncore));
>
> - intel_uncore_fw_domains_init(uncore);
> + ret = intel_uncore_fw_domains_init(uncore);
> + if (ret)
> + return ret;
> +
> forcewake_early_sanitize(uncore, 0);
>
> if (IS_GEN_RANGE(i915, 6, 7)) {
> @@ -1601,6 +1631,8 @@ static void uncore_forcewake_init(struct intel_uncore *uncore)
>
> uncore->pmic_bus_access_nb.notifier_call = i915_pmic_bus_access_notifier;
> iosf_mbi_register_pmic_bus_access_notifier(&uncore->pmic_bus_access_nb);
> +
> + return 0;
> }
>
> int intel_uncore_init_mmio(struct intel_uncore *uncore)
> @@ -1619,10 +1651,13 @@ int intel_uncore_init_mmio(struct intel_uncore *uncore)
>
> uncore->unclaimed_mmio_check = 1;
>
> - if (!intel_uncore_has_forcewake(uncore))
> + if (!intel_uncore_has_forcewake(uncore)) {
> uncore_raw_init(uncore);
> - else
> - uncore_forcewake_init(uncore);
> + } else {
> + ret = uncore_forcewake_init(uncore);
> + if (ret)
> + goto out_mmio_cleanup;
> + }
>
> /* make sure fw funcs are set if and only if we have fw*/
> GEM_BUG_ON(intel_uncore_has_forcewake(uncore) != !!uncore->funcs.force_wake_get);
> @@ -1644,6 +1679,11 @@ int intel_uncore_init_mmio(struct intel_uncore *uncore)
> DRM_DEBUG("unclaimed mmio detected on uncore init, clearing\n");
>
> return 0;
> +
> +out_mmio_cleanup:
> + uncore_mmio_cleanup(uncore);
> +
> + return ret;
> }
>
> /*
> @@ -1689,6 +1729,7 @@ void intel_uncore_fini_mmio(struct intel_uncore *uncore)
> iosf_mbi_unregister_pmic_bus_access_notifier_unlocked(
> &uncore->pmic_bus_access_nb);
> intel_uncore_forcewake_reset(uncore);
> + intel_uncore_fw_domains_fini(uncore);
> iosf_mbi_punit_release();
> }
>
> diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h
> index 879252735bba..bbff281b880d 100644
> --- a/drivers/gpu/drm/i915/intel_uncore.h
> +++ b/drivers/gpu/drm/i915/intel_uncore.h
> @@ -126,6 +126,7 @@ struct intel_uncore {
> enum forcewake_domains fw_domains_saved; /* user domains saved for S3 */
>
> struct intel_uncore_forcewake_domain {
> + struct intel_uncore *uncore;
> enum forcewake_domain_id id;
> enum forcewake_domains mask;
> unsigned int wake_count;
> @@ -133,7 +134,7 @@ struct intel_uncore {
> struct hrtimer timer;
> u32 __iomem *reg_set;
> u32 __iomem *reg_ack;
> - } fw_domain[FW_DOMAIN_ID_COUNT];
> + } *fw_domain[FW_DOMAIN_ID_COUNT];
The array itself could also be made dynamic, no? To much hassle for very
little gain?
>
> struct {
> unsigned int count;
> @@ -147,18 +148,12 @@ struct intel_uncore {
>
> /* Iterate over initialised fw domains */
> #define for_each_fw_domain_masked(domain__, mask__, uncore__, tmp__) \
> - for (tmp__ = (mask__); \
> - tmp__ ? (domain__ = &(uncore__)->fw_domain[__mask_next_bit(tmp__)]), 1 : 0;)
> + for (tmp__ = (mask__); tmp__ ;) \
> + for_each_if(domain__ = (uncore__)->fw_domain[__mask_next_bit(tmp__)])
>
> #define for_each_fw_domain(domain__, uncore__, tmp__) \
> for_each_fw_domain_masked(domain__, (uncore__)->fw_domains, uncore__, tmp__)
>
> -static inline struct intel_uncore *
> -forcewake_domain_to_uncore(const struct intel_uncore_forcewake_domain *d)
> -{
> - return container_of(d, struct intel_uncore, fw_domain[d->id]);
> -}
> -
> static inline bool
> intel_uncore_has_forcewake(const struct intel_uncore *uncore)
> {
>
Regards,
Tvrtko
More information about the Intel-gfx
mailing list