[Intel-gfx] [PATCH v2 5/6] drm/i915: dynamically allocate forcewake domains

Chris Wilson chris at chris-wilson.co.uk
Thu Jun 20 07:55:19 UTC 2019


Quoting Daniele Ceraolo Spurio (2019-06-20 02:00:20)
> 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.
> 
> v2: avoid hidden control flow, improve checks (Tvrtko), fix IVB special
> case, add failure injection point
> 
> Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio at intel.com>
> Cc: Tvrtko Ursulin <tvrtko.ursulin at linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_uncore.c | 101 ++++++++++++++++++++--------
>  drivers/gpu/drm/i915/intel_uncore.h |  13 ++--
>  2 files changed, 77 insertions(+), 37 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_uncore.c b/drivers/gpu/drm/i915/intel_uncore.c
> index 00bf5e085a2c..2bd602a41bb7 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);
> @@ -1293,23 +1293,27 @@ do { \
>         (uncore)->funcs.read_fw_domains = x##_reg_read_fw_domains; \
>  } while (0)
>  
> -static void fw_domain_init(struct intel_uncore *uncore,
> -                          enum forcewake_domain_id domain_id,
> -                          i915_reg_t reg_set,
> -                          i915_reg_t reg_ack)
> +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;
> +       GEM_BUG_ON(domain_id >= FW_DOMAIN_ID_COUNT);
> +       GEM_BUG_ON(uncore->fw_domain[domain_id]);
>  
> -       d = &uncore->fw_domain[domain_id];
> +       if (i915_inject_load_failure())
> +               return -ENOMEM;

Will be an interesting test for the test (well dmesg parser to see if it
is still getting upset over nothing).

> -       WARN_ON(d->wake_count);
> +       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);
> @@ -1326,7 +1330,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);
> @@ -1335,6 +1338,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;

Fwiw, I would pair this with setting the mask in uncore->fw_domains.

> +
> +       return 0;
>  }
>  
>  static void fw_domain_fini(struct intel_uncore *uncore,
> @@ -1342,29 +1349,41 @@ 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]);
> +       if (!d)
> +               return;
>  
> +       uncore->fw_domains &= ~BIT(domain_id);
>         WARN_ON(d->wake_count);
>         WARN_ON(hrtimer_cancel(&d->timer));
> -       memset(d, 0, sizeof(*d));
> +       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 = 0;
>  
>         GEM_BUG_ON(!intel_uncore_has_forcewake(uncore));
>  
> +#define fw_domain_init(uncore__, id__, set__, ack__) \
> +       (ret ?: (ret = __fw_domain_init((uncore__), (id__), (set__), (ack__))))

Seems a reasonable compromise, that I'm sure we'll live to regret. :)

>         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,
> @@ -1372,6 +1391,7 @@ static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
>                 fw_domain_init(uncore, 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;
> @@ -1389,8 +1409,7 @@ static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
>                                        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,
> @@ -1439,8 +1458,10 @@ 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);
> +               ret = __fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
> +                                      FORCEWAKE_MT, FORCEWAKE_MT_ACK);
> +               if (ret)
> +                       goto out;
>  
>                 spin_lock_irq(&uncore->lock);
>                 fw_domains_get_with_thread_status(uncore, FORCEWAKE_RENDER);
> @@ -1451,6 +1472,7 @@ 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_fini(uncore, FW_DOMAIN_ID_RENDER);
>                         fw_domain_init(uncore, FW_DOMAIN_ID_RENDER,
>                                        FORCEWAKE, FORCEWAKE_ACK);
>                 }
> @@ -1462,8 +1484,16 @@ static void intel_uncore_fw_domains_init(struct intel_uncore *uncore)
>                                FORCEWAKE, FORCEWAKE_ACK);
>         }
>  
> +#undef fw_domain_init
> +
>         /* All future platforms are expected to require complex power gating */
> -       WARN_ON(uncore->fw_domains == 0);
> +       WARN_ON(!ret && uncore->fw_domains == 0);
> +
> +out:
> +       if (ret)
> +               intel_uncore_fw_domains_fini(uncore);
> +
> +       return ret;
>  }
>  
>  #define ASSIGN_FW_DOMAINS_TABLE(uncore, d) \
> @@ -1564,13 +1594,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)) {
> @@ -1603,6 +1637,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)
> @@ -1621,10 +1657,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);
> @@ -1646,6 +1685,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;
>  }
>  
>  /*
> @@ -1691,6 +1735,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);

Ok, looks like this is paired correctly. I suppose we can't do the
allocations any earlier, and it does make sense that we can't detect the
domains until we can probe the HW so mmio.

>                 iosf_mbi_punit_release();
>         }
>  
> diff --git a/drivers/gpu/drm/i915/intel_uncore.h b/drivers/gpu/drm/i915/intel_uncore.h
> index 59505a2f9097..7108475d9b24 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];

How long before we start using a tree for the countless domains :)

>  
>         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)
>  {

Reviewed-by: Chris Wilson <chris at chris-wilson.co.uk>
-Chris


More information about the Intel-gfx mailing list