Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 2016 Intel Corporation
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice (including the next
0012  * paragraph) shall be included in all copies or substantial portions of the
0013  * Software.
0014  *
0015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0018  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0020  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
0021  * IN THE SOFTWARE.
0022  *
0023  */
0024 
0025 #include "../i915_selftest.h"
0026 
0027 static int intel_fw_table_check(const struct intel_forcewake_range *ranges,
0028                 unsigned int num_ranges,
0029                 bool is_watertight)
0030 {
0031     unsigned int i;
0032     s32 prev;
0033 
0034     for (i = 0, prev = -1; i < num_ranges; i++, ranges++) {
0035         /* Check that the table is watertight */
0036         if (is_watertight && (prev + 1) != (s32)ranges->start) {
0037             pr_err("%s: entry[%d]:(%x, %x) is not watertight to previous (%x)\n",
0038                    __func__, i, ranges->start, ranges->end, prev);
0039             return -EINVAL;
0040         }
0041 
0042         /* Check that the table never goes backwards */
0043         if (prev >= (s32)ranges->start) {
0044             pr_err("%s: entry[%d]:(%x, %x) is less than the previous (%x)\n",
0045                    __func__, i, ranges->start, ranges->end, prev);
0046             return -EINVAL;
0047         }
0048 
0049         /* Check that the entry is valid */
0050         if (ranges->start >= ranges->end) {
0051             pr_err("%s: entry[%d]:(%x, %x) has negative length\n",
0052                    __func__, i, ranges->start, ranges->end);
0053             return -EINVAL;
0054         }
0055 
0056         prev = ranges->end;
0057     }
0058 
0059     return 0;
0060 }
0061 
0062 static int intel_shadow_table_check(void)
0063 {
0064     struct {
0065         const struct i915_range *regs;
0066         unsigned int size;
0067     } range_lists[] = {
0068         { gen8_shadowed_regs, ARRAY_SIZE(gen8_shadowed_regs) },
0069         { gen11_shadowed_regs, ARRAY_SIZE(gen11_shadowed_regs) },
0070         { gen12_shadowed_regs, ARRAY_SIZE(gen12_shadowed_regs) },
0071         { dg2_shadowed_regs, ARRAY_SIZE(dg2_shadowed_regs) },
0072         { pvc_shadowed_regs, ARRAY_SIZE(pvc_shadowed_regs) },
0073     };
0074     const struct i915_range *range;
0075     unsigned int i, j;
0076     s32 prev;
0077 
0078     for (j = 0; j < ARRAY_SIZE(range_lists); ++j) {
0079         range = range_lists[j].regs;
0080         for (i = 0, prev = -1; i < range_lists[j].size; i++, range++) {
0081             if (range->end < range->start) {
0082                 pr_err("%s: range[%d]:(%06x-%06x) has end before start\n",
0083                        __func__, i, range->start, range->end);
0084                 return -EINVAL;
0085             }
0086 
0087             if (prev >= (s32)range->start) {
0088                 pr_err("%s: range[%d]:(%06x-%06x) is before end of previous (%06x)\n",
0089                        __func__, i, range->start, range->end, prev);
0090                 return -EINVAL;
0091             }
0092 
0093             if (range->start % 4) {
0094                 pr_err("%s: range[%d]:(%06x-%06x) has non-dword-aligned start\n",
0095                        __func__, i, range->start, range->end);
0096                 return -EINVAL;
0097             }
0098 
0099             prev = range->end;
0100         }
0101     }
0102 
0103     return 0;
0104 }
0105 
0106 int intel_uncore_mock_selftests(void)
0107 {
0108     struct {
0109         const struct intel_forcewake_range *ranges;
0110         unsigned int num_ranges;
0111         bool is_watertight;
0112     } fw[] = {
0113         { __vlv_fw_ranges, ARRAY_SIZE(__vlv_fw_ranges), false },
0114         { __chv_fw_ranges, ARRAY_SIZE(__chv_fw_ranges), false },
0115         { __gen9_fw_ranges, ARRAY_SIZE(__gen9_fw_ranges), true },
0116         { __gen11_fw_ranges, ARRAY_SIZE(__gen11_fw_ranges), true },
0117         { __gen12_fw_ranges, ARRAY_SIZE(__gen12_fw_ranges), true },
0118         { __xehp_fw_ranges, ARRAY_SIZE(__xehp_fw_ranges), true },
0119         { __pvc_fw_ranges, ARRAY_SIZE(__pvc_fw_ranges), true },
0120     };
0121     int err, i;
0122 
0123     for (i = 0; i < ARRAY_SIZE(fw); i++) {
0124         err = intel_fw_table_check(fw[i].ranges,
0125                        fw[i].num_ranges,
0126                        fw[i].is_watertight);
0127         if (err)
0128             return err;
0129     }
0130 
0131     err = intel_shadow_table_check();
0132     if (err)
0133         return err;
0134 
0135     return 0;
0136 }
0137 
0138 static int live_forcewake_ops(void *arg)
0139 {
0140     static const struct reg {
0141         const char *name;
0142         u8 min_graphics_ver;
0143         u8 max_graphics_ver;
0144         unsigned long platforms;
0145         unsigned int offset;
0146     } registers[] = {
0147         {
0148             "RING_START",
0149             6, 7,
0150             0x38,
0151         },
0152         {
0153             "RING_MI_MODE",
0154             8, U8_MAX,
0155             0x9c,
0156         }
0157     };
0158     const struct reg *r;
0159     struct intel_gt *gt = arg;
0160     struct intel_uncore_forcewake_domain *domain;
0161     struct intel_uncore *uncore = gt->uncore;
0162     struct intel_engine_cs *engine;
0163     enum intel_engine_id id;
0164     intel_wakeref_t wakeref;
0165     unsigned int tmp;
0166     int err = 0;
0167 
0168     GEM_BUG_ON(gt->awake);
0169 
0170     /* vlv/chv with their pcu behave differently wrt reads */
0171     if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915)) {
0172         pr_debug("PCU fakes forcewake badly; skipping\n");
0173         return 0;
0174     }
0175 
0176     /*
0177      * Not quite as reliable across the gen as one would hope.
0178      *
0179      * Either our theory of operation is incorrect, or there remain
0180      * external parties interfering with the powerwells.
0181      *
0182      * https://bugs.freedesktop.org/show_bug.cgi?id=110210
0183      */
0184     if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN))
0185         return 0;
0186 
0187     /* We have to pick carefully to get the exact behaviour we need */
0188     for (r = registers; r->name; r++)
0189         if (IS_GRAPHICS_VER(gt->i915, r->min_graphics_ver, r->max_graphics_ver))
0190             break;
0191     if (!r->name) {
0192         pr_debug("Forcewaked register not known for %s; skipping\n",
0193              intel_platform_name(INTEL_INFO(gt->i915)->platform));
0194         return 0;
0195     }
0196 
0197     wakeref = intel_runtime_pm_get(uncore->rpm);
0198 
0199     for_each_fw_domain(domain, uncore, tmp) {
0200         smp_store_mb(domain->active, false);
0201         if (!hrtimer_cancel(&domain->timer))
0202             continue;
0203 
0204         intel_uncore_fw_release_timer(&domain->timer);
0205     }
0206 
0207     for_each_engine(engine, gt, id) {
0208         i915_reg_t mmio = _MMIO(engine->mmio_base + r->offset);
0209         u32 __iomem *reg = uncore->regs + engine->mmio_base + r->offset;
0210         enum forcewake_domains fw_domains;
0211         u32 val;
0212 
0213         if (!engine->default_state)
0214             continue;
0215 
0216         fw_domains = intel_uncore_forcewake_for_reg(uncore, mmio,
0217                                 FW_REG_READ);
0218         if (!fw_domains)
0219             continue;
0220 
0221         for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) {
0222             if (!domain->wake_count)
0223                 continue;
0224 
0225             pr_err("fw_domain %s still active, aborting test!\n",
0226                    intel_uncore_forcewake_domain_to_str(domain->id));
0227             err = -EINVAL;
0228             goto out_rpm;
0229         }
0230 
0231         intel_uncore_forcewake_get(uncore, fw_domains);
0232         val = readl(reg);
0233         intel_uncore_forcewake_put(uncore, fw_domains);
0234 
0235         /* Flush the forcewake release (delayed onto a timer) */
0236         for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) {
0237             smp_store_mb(domain->active, false);
0238             if (hrtimer_cancel(&domain->timer))
0239                 intel_uncore_fw_release_timer(&domain->timer);
0240 
0241             preempt_disable();
0242             err = wait_ack_clear(domain, FORCEWAKE_KERNEL);
0243             preempt_enable();
0244             if (err) {
0245                 pr_err("Failed to clear fw_domain %s\n",
0246                        intel_uncore_forcewake_domain_to_str(domain->id));
0247                 goto out_rpm;
0248             }
0249         }
0250 
0251         if (!val) {
0252             pr_err("%s:%s was zero while fw was held!\n",
0253                    engine->name, r->name);
0254             err = -EINVAL;
0255             goto out_rpm;
0256         }
0257 
0258         /* We then expect the read to return 0 outside of the fw */
0259         if (wait_for(readl(reg) == 0, 100)) {
0260             pr_err("%s:%s=%0x, fw_domains 0x%x still up after 100ms!\n",
0261                    engine->name, r->name, readl(reg), fw_domains);
0262             err = -ETIMEDOUT;
0263             goto out_rpm;
0264         }
0265     }
0266 
0267 out_rpm:
0268     intel_runtime_pm_put(uncore->rpm, wakeref);
0269     return err;
0270 }
0271 
0272 static int live_forcewake_domains(void *arg)
0273 {
0274 #define FW_RANGE 0x40000
0275     struct intel_gt *gt = arg;
0276     struct intel_uncore *uncore = gt->uncore;
0277     unsigned long *valid;
0278     u32 offset;
0279     int err;
0280 
0281     if (!HAS_FPGA_DBG_UNCLAIMED(gt->i915) &&
0282         !IS_VALLEYVIEW(gt->i915) &&
0283         !IS_CHERRYVIEW(gt->i915))
0284         return 0;
0285 
0286     /*
0287      * This test may lockup the machine or cause GPU hangs afterwards.
0288      */
0289     if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN))
0290         return 0;
0291 
0292     valid = bitmap_zalloc(FW_RANGE, GFP_KERNEL);
0293     if (!valid)
0294         return -ENOMEM;
0295 
0296     intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL);
0297 
0298     check_for_unclaimed_mmio(uncore);
0299     for (offset = 0; offset < FW_RANGE; offset += 4) {
0300         i915_reg_t reg = { offset };
0301 
0302         intel_uncore_posting_read_fw(uncore, reg);
0303         if (!check_for_unclaimed_mmio(uncore))
0304             set_bit(offset, valid);
0305     }
0306 
0307     intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL);
0308 
0309     err = 0;
0310     for_each_set_bit(offset, valid, FW_RANGE) {
0311         i915_reg_t reg = { offset };
0312 
0313         iosf_mbi_punit_acquire();
0314         intel_uncore_forcewake_reset(uncore);
0315         iosf_mbi_punit_release();
0316 
0317         check_for_unclaimed_mmio(uncore);
0318 
0319         intel_uncore_posting_read_fw(uncore, reg);
0320         if (check_for_unclaimed_mmio(uncore)) {
0321             pr_err("Unclaimed mmio read to register 0x%04x\n",
0322                    offset);
0323             err = -EINVAL;
0324         }
0325     }
0326 
0327     bitmap_free(valid);
0328     return err;
0329 }
0330 
0331 static int live_fw_table(void *arg)
0332 {
0333     struct intel_gt *gt = arg;
0334 
0335     /* Confirm the table we load is still valid */
0336     return intel_fw_table_check(gt->uncore->fw_domains_table,
0337                     gt->uncore->fw_domains_table_entries,
0338                     GRAPHICS_VER(gt->i915) >= 9);
0339 }
0340 
0341 int intel_uncore_live_selftests(struct drm_i915_private *i915)
0342 {
0343     static const struct i915_subtest tests[] = {
0344         SUBTEST(live_fw_table),
0345         SUBTEST(live_forcewake_ops),
0346         SUBTEST(live_forcewake_domains),
0347     };
0348 
0349     return intel_gt_live_subtests(tests, to_gt(i915));
0350 }