return 0;
 }
 
-static int intel_uncore_check_forcewake_domains(struct drm_i915_private *dev_priv)
+static int live_forcewake_ops(void *arg)
+{
+       static const struct reg {
+               const char *name;
+               unsigned long platforms;
+               unsigned int offset;
+       } registers[] = {
+               {
+                       "RING_START",
+                       INTEL_GEN_MASK(6, 7),
+                       0x38,
+               },
+               {
+                       "RING_MI_MODE",
+                       INTEL_GEN_MASK(8, BITS_PER_LONG),
+                       0x9c,
+               }
+       };
+       const struct reg *r;
+       struct drm_i915_private *i915 = arg;
+       struct intel_uncore_forcewake_domain *domain;
+       struct intel_engine_cs *engine;
+       enum intel_engine_id id;
+       intel_wakeref_t wakeref;
+       unsigned int tmp;
+       int err = 0;
+
+       GEM_BUG_ON(i915->gt.awake);
+
+       /* vlv/chv with their pcu behave differently wrt reads */
+       if (IS_VALLEYVIEW(i915) || IS_CHERRYVIEW(i915)) {
+               pr_debug("PCU fakes forcewake badly; skipping\n");
+               return 0;
+       }
+
+       /* We have to pick carefully to get the exact behaviour we need */
+       for (r = registers; r->name; r++)
+               if (r->platforms & INTEL_INFO(i915)->gen_mask)
+                       break;
+       if (!r->name) {
+               pr_debug("Forcewaked register not known for %s; skipping\n",
+                        intel_platform_name(INTEL_INFO(i915)->platform));
+               return 0;
+       }
+
+       wakeref = intel_runtime_pm_get(i915);
+
+       for_each_fw_domain(domain, i915, tmp) {
+               smp_store_mb(domain->active, false);
+               if (!hrtimer_cancel(&domain->timer))
+                       continue;
+
+               intel_uncore_fw_release_timer(&domain->timer);
+       }
+
+       for_each_engine(engine, i915, id) {
+               i915_reg_t mmio = _MMIO(engine->mmio_base + r->offset);
+               u32 __iomem *reg = i915->regs + engine->mmio_base + r->offset;
+               enum forcewake_domains fw_domains;
+               u32 val;
+
+               if (!engine->default_state)
+                       continue;
+
+               fw_domains = intel_uncore_forcewake_for_reg(i915, mmio,
+                                                           FW_REG_READ);
+               if (!fw_domains)
+                       continue;
+
+               for_each_fw_domain_masked(domain, fw_domains, i915, tmp) {
+                       if (!domain->wake_count)
+                               continue;
+
+                       pr_err("fw_domain %s still active, aborting test!\n",
+                              intel_uncore_forcewake_domain_to_str(domain->id));
+                       err = -EINVAL;
+                       goto out_rpm;
+               }
+
+               intel_uncore_forcewake_get(i915, fw_domains);
+               val = readl(reg);
+               intel_uncore_forcewake_put(i915, fw_domains);
+
+               /* Flush the forcewake release (delayed onto a timer) */
+               for_each_fw_domain_masked(domain, fw_domains, i915, tmp) {
+                       smp_store_mb(domain->active, false);
+                       if (hrtimer_cancel(&domain->timer))
+                               intel_uncore_fw_release_timer(&domain->timer);
+
+                       preempt_disable();
+                       err = wait_ack_clear(domain, FORCEWAKE_KERNEL);
+                       preempt_enable();
+                       if (err) {
+                               pr_err("Failed to clear fw_domain %s\n",
+                                      intel_uncore_forcewake_domain_to_str(domain->id));
+                               goto out_rpm;
+                       }
+               }
+
+               if (!val) {
+                       pr_err("%s:%s was zero while fw was held!\n",
+                              engine->name, r->name);
+                       err = -EINVAL;
+                       goto out_rpm;
+               }
+
+               /* We then expect the read to return 0 outside of the fw */
+               if (wait_for(readl(reg) == 0, 100)) {
+                       pr_err("%s:%s=%0x, fw_domains 0x%x still up after 100ms!\n",
+                              engine->name, r->name, readl(reg), fw_domains);
+                       err = -ETIMEDOUT;
+                       goto out_rpm;
+               }
+       }
+
+out_rpm:
+       intel_runtime_pm_put(i915, wakeref);
+       return err;
+}
+
+static int live_forcewake_domains(void *arg)
 {
 #define FW_RANGE 0x40000
+       struct drm_i915_private *dev_priv = arg;
        unsigned long *valid;
        u32 offset;
        int err;
 
 int intel_uncore_live_selftests(struct drm_i915_private *i915)
 {
+       static const struct i915_subtest tests[] = {
+               SUBTEST(live_forcewake_ops),
+               SUBTEST(live_forcewake_domains),
+       };
+
        int err;
 
        /* Confirm the table we load is still valid */
        if (err)
                return err;
 
-       err = intel_uncore_check_forcewake_domains(i915);
-       if (err)
-               return err;
-
-       return 0;
+       return i915_subtests(tests, i915);
 }