.. | .. |
---|
67 | 67 | } reg_lists[] = { |
---|
68 | 68 | { gen8_shadowed_regs, ARRAY_SIZE(gen8_shadowed_regs) }, |
---|
69 | 69 | { gen11_shadowed_regs, ARRAY_SIZE(gen11_shadowed_regs) }, |
---|
| 70 | + { gen12_shadowed_regs, ARRAY_SIZE(gen12_shadowed_regs) }, |
---|
70 | 71 | }; |
---|
71 | 72 | const i915_reg_t *reg; |
---|
72 | 73 | unsigned int i, j; |
---|
.. | .. |
---|
101 | 102 | { __chv_fw_ranges, ARRAY_SIZE(__chv_fw_ranges), false }, |
---|
102 | 103 | { __gen9_fw_ranges, ARRAY_SIZE(__gen9_fw_ranges), true }, |
---|
103 | 104 | { __gen11_fw_ranges, ARRAY_SIZE(__gen11_fw_ranges), true }, |
---|
| 105 | + { __gen12_fw_ranges, ARRAY_SIZE(__gen12_fw_ranges), true }, |
---|
104 | 106 | }; |
---|
105 | 107 | int err, i; |
---|
106 | 108 | |
---|
.. | .. |
---|
119 | 121 | return 0; |
---|
120 | 122 | } |
---|
121 | 123 | |
---|
122 | | -static int intel_uncore_check_forcewake_domains(struct drm_i915_private *dev_priv) |
---|
| 124 | +static int live_forcewake_ops(void *arg) |
---|
| 125 | +{ |
---|
| 126 | + static const struct reg { |
---|
| 127 | + const char *name; |
---|
| 128 | + unsigned long platforms; |
---|
| 129 | + unsigned int offset; |
---|
| 130 | + } registers[] = { |
---|
| 131 | + { |
---|
| 132 | + "RING_START", |
---|
| 133 | + INTEL_GEN_MASK(6, 7), |
---|
| 134 | + 0x38, |
---|
| 135 | + }, |
---|
| 136 | + { |
---|
| 137 | + "RING_MI_MODE", |
---|
| 138 | + INTEL_GEN_MASK(8, BITS_PER_LONG), |
---|
| 139 | + 0x9c, |
---|
| 140 | + } |
---|
| 141 | + }; |
---|
| 142 | + const struct reg *r; |
---|
| 143 | + struct intel_gt *gt = arg; |
---|
| 144 | + struct intel_uncore_forcewake_domain *domain; |
---|
| 145 | + struct intel_uncore *uncore = gt->uncore; |
---|
| 146 | + struct intel_engine_cs *engine; |
---|
| 147 | + enum intel_engine_id id; |
---|
| 148 | + intel_wakeref_t wakeref; |
---|
| 149 | + unsigned int tmp; |
---|
| 150 | + int err = 0; |
---|
| 151 | + |
---|
| 152 | + GEM_BUG_ON(gt->awake); |
---|
| 153 | + |
---|
| 154 | + /* vlv/chv with their pcu behave differently wrt reads */ |
---|
| 155 | + if (IS_VALLEYVIEW(gt->i915) || IS_CHERRYVIEW(gt->i915)) { |
---|
| 156 | + pr_debug("PCU fakes forcewake badly; skipping\n"); |
---|
| 157 | + return 0; |
---|
| 158 | + } |
---|
| 159 | + |
---|
| 160 | + /* |
---|
| 161 | + * Not quite as reliable across the gen as one would hope. |
---|
| 162 | + * |
---|
| 163 | + * Either our theory of operation is incorrect, or there remain |
---|
| 164 | + * external parties interfering with the powerwells. |
---|
| 165 | + * |
---|
| 166 | + * https://bugs.freedesktop.org/show_bug.cgi?id=110210 |
---|
| 167 | + */ |
---|
| 168 | + if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN)) |
---|
| 169 | + return 0; |
---|
| 170 | + |
---|
| 171 | + /* We have to pick carefully to get the exact behaviour we need */ |
---|
| 172 | + for (r = registers; r->name; r++) |
---|
| 173 | + if (r->platforms & INTEL_INFO(gt->i915)->gen_mask) |
---|
| 174 | + break; |
---|
| 175 | + if (!r->name) { |
---|
| 176 | + pr_debug("Forcewaked register not known for %s; skipping\n", |
---|
| 177 | + intel_platform_name(INTEL_INFO(gt->i915)->platform)); |
---|
| 178 | + return 0; |
---|
| 179 | + } |
---|
| 180 | + |
---|
| 181 | + wakeref = intel_runtime_pm_get(uncore->rpm); |
---|
| 182 | + |
---|
| 183 | + for_each_fw_domain(domain, uncore, tmp) { |
---|
| 184 | + smp_store_mb(domain->active, false); |
---|
| 185 | + if (!hrtimer_cancel(&domain->timer)) |
---|
| 186 | + continue; |
---|
| 187 | + |
---|
| 188 | + intel_uncore_fw_release_timer(&domain->timer); |
---|
| 189 | + } |
---|
| 190 | + |
---|
| 191 | + for_each_engine(engine, gt, id) { |
---|
| 192 | + i915_reg_t mmio = _MMIO(engine->mmio_base + r->offset); |
---|
| 193 | + u32 __iomem *reg = uncore->regs + engine->mmio_base + r->offset; |
---|
| 194 | + enum forcewake_domains fw_domains; |
---|
| 195 | + u32 val; |
---|
| 196 | + |
---|
| 197 | + if (!engine->default_state) |
---|
| 198 | + continue; |
---|
| 199 | + |
---|
| 200 | + fw_domains = intel_uncore_forcewake_for_reg(uncore, mmio, |
---|
| 201 | + FW_REG_READ); |
---|
| 202 | + if (!fw_domains) |
---|
| 203 | + continue; |
---|
| 204 | + |
---|
| 205 | + for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) { |
---|
| 206 | + if (!domain->wake_count) |
---|
| 207 | + continue; |
---|
| 208 | + |
---|
| 209 | + pr_err("fw_domain %s still active, aborting test!\n", |
---|
| 210 | + intel_uncore_forcewake_domain_to_str(domain->id)); |
---|
| 211 | + err = -EINVAL; |
---|
| 212 | + goto out_rpm; |
---|
| 213 | + } |
---|
| 214 | + |
---|
| 215 | + intel_uncore_forcewake_get(uncore, fw_domains); |
---|
| 216 | + val = readl(reg); |
---|
| 217 | + intel_uncore_forcewake_put(uncore, fw_domains); |
---|
| 218 | + |
---|
| 219 | + /* Flush the forcewake release (delayed onto a timer) */ |
---|
| 220 | + for_each_fw_domain_masked(domain, fw_domains, uncore, tmp) { |
---|
| 221 | + smp_store_mb(domain->active, false); |
---|
| 222 | + if (hrtimer_cancel(&domain->timer)) |
---|
| 223 | + intel_uncore_fw_release_timer(&domain->timer); |
---|
| 224 | + |
---|
| 225 | + preempt_disable(); |
---|
| 226 | + err = wait_ack_clear(domain, FORCEWAKE_KERNEL); |
---|
| 227 | + preempt_enable(); |
---|
| 228 | + if (err) { |
---|
| 229 | + pr_err("Failed to clear fw_domain %s\n", |
---|
| 230 | + intel_uncore_forcewake_domain_to_str(domain->id)); |
---|
| 231 | + goto out_rpm; |
---|
| 232 | + } |
---|
| 233 | + } |
---|
| 234 | + |
---|
| 235 | + if (!val) { |
---|
| 236 | + pr_err("%s:%s was zero while fw was held!\n", |
---|
| 237 | + engine->name, r->name); |
---|
| 238 | + err = -EINVAL; |
---|
| 239 | + goto out_rpm; |
---|
| 240 | + } |
---|
| 241 | + |
---|
| 242 | + /* We then expect the read to return 0 outside of the fw */ |
---|
| 243 | + if (wait_for(readl(reg) == 0, 100)) { |
---|
| 244 | + pr_err("%s:%s=%0x, fw_domains 0x%x still up after 100ms!\n", |
---|
| 245 | + engine->name, r->name, readl(reg), fw_domains); |
---|
| 246 | + err = -ETIMEDOUT; |
---|
| 247 | + goto out_rpm; |
---|
| 248 | + } |
---|
| 249 | + } |
---|
| 250 | + |
---|
| 251 | +out_rpm: |
---|
| 252 | + intel_runtime_pm_put(uncore->rpm, wakeref); |
---|
| 253 | + return err; |
---|
| 254 | +} |
---|
| 255 | + |
---|
| 256 | +static int live_forcewake_domains(void *arg) |
---|
123 | 257 | { |
---|
124 | 258 | #define FW_RANGE 0x40000 |
---|
| 259 | + struct intel_gt *gt = arg; |
---|
| 260 | + struct intel_uncore *uncore = gt->uncore; |
---|
125 | 261 | unsigned long *valid; |
---|
126 | 262 | u32 offset; |
---|
127 | 263 | int err; |
---|
128 | 264 | |
---|
129 | | - if (!HAS_FPGA_DBG_UNCLAIMED(dev_priv) && |
---|
130 | | - !IS_VALLEYVIEW(dev_priv) && |
---|
131 | | - !IS_CHERRYVIEW(dev_priv)) |
---|
| 265 | + if (!HAS_FPGA_DBG_UNCLAIMED(gt->i915) && |
---|
| 266 | + !IS_VALLEYVIEW(gt->i915) && |
---|
| 267 | + !IS_CHERRYVIEW(gt->i915)) |
---|
132 | 268 | return 0; |
---|
133 | 269 | |
---|
134 | 270 | /* |
---|
.. | .. |
---|
137 | 273 | if (!IS_ENABLED(CONFIG_DRM_I915_SELFTEST_BROKEN)) |
---|
138 | 274 | return 0; |
---|
139 | 275 | |
---|
140 | | - valid = kcalloc(BITS_TO_LONGS(FW_RANGE), sizeof(*valid), |
---|
141 | | - GFP_KERNEL); |
---|
| 276 | + valid = bitmap_zalloc(FW_RANGE, GFP_KERNEL); |
---|
142 | 277 | if (!valid) |
---|
143 | 278 | return -ENOMEM; |
---|
144 | 279 | |
---|
145 | | - intel_uncore_forcewake_get(dev_priv, FORCEWAKE_ALL); |
---|
| 280 | + intel_uncore_forcewake_get(uncore, FORCEWAKE_ALL); |
---|
146 | 281 | |
---|
147 | | - check_for_unclaimed_mmio(dev_priv); |
---|
| 282 | + check_for_unclaimed_mmio(uncore); |
---|
148 | 283 | for (offset = 0; offset < FW_RANGE; offset += 4) { |
---|
149 | 284 | i915_reg_t reg = { offset }; |
---|
150 | 285 | |
---|
151 | | - (void)I915_READ_FW(reg); |
---|
152 | | - if (!check_for_unclaimed_mmio(dev_priv)) |
---|
| 286 | + intel_uncore_posting_read_fw(uncore, reg); |
---|
| 287 | + if (!check_for_unclaimed_mmio(uncore)) |
---|
153 | 288 | set_bit(offset, valid); |
---|
154 | 289 | } |
---|
155 | 290 | |
---|
156 | | - intel_uncore_forcewake_put(dev_priv, FORCEWAKE_ALL); |
---|
| 291 | + intel_uncore_forcewake_put(uncore, FORCEWAKE_ALL); |
---|
157 | 292 | |
---|
158 | 293 | err = 0; |
---|
159 | 294 | for_each_set_bit(offset, valid, FW_RANGE) { |
---|
160 | 295 | i915_reg_t reg = { offset }; |
---|
161 | 296 | |
---|
162 | 297 | iosf_mbi_punit_acquire(); |
---|
163 | | - intel_uncore_forcewake_reset(dev_priv); |
---|
| 298 | + intel_uncore_forcewake_reset(uncore); |
---|
164 | 299 | iosf_mbi_punit_release(); |
---|
165 | 300 | |
---|
166 | | - check_for_unclaimed_mmio(dev_priv); |
---|
| 301 | + check_for_unclaimed_mmio(uncore); |
---|
167 | 302 | |
---|
168 | | - (void)I915_READ(reg); |
---|
169 | | - if (check_for_unclaimed_mmio(dev_priv)) { |
---|
| 303 | + intel_uncore_posting_read_fw(uncore, reg); |
---|
| 304 | + if (check_for_unclaimed_mmio(uncore)) { |
---|
170 | 305 | pr_err("Unclaimed mmio read to register 0x%04x\n", |
---|
171 | 306 | offset); |
---|
172 | 307 | err = -EINVAL; |
---|
173 | 308 | } |
---|
174 | 309 | } |
---|
175 | 310 | |
---|
176 | | - kfree(valid); |
---|
| 311 | + bitmap_free(valid); |
---|
177 | 312 | return err; |
---|
| 313 | +} |
---|
| 314 | + |
---|
| 315 | +static int live_fw_table(void *arg) |
---|
| 316 | +{ |
---|
| 317 | + struct intel_gt *gt = arg; |
---|
| 318 | + |
---|
| 319 | + /* Confirm the table we load is still valid */ |
---|
| 320 | + return intel_fw_table_check(gt->uncore->fw_domains_table, |
---|
| 321 | + gt->uncore->fw_domains_table_entries, |
---|
| 322 | + INTEL_GEN(gt->i915) >= 9); |
---|
178 | 323 | } |
---|
179 | 324 | |
---|
180 | 325 | int intel_uncore_live_selftests(struct drm_i915_private *i915) |
---|
181 | 326 | { |
---|
182 | | - int err; |
---|
| 327 | + static const struct i915_subtest tests[] = { |
---|
| 328 | + SUBTEST(live_fw_table), |
---|
| 329 | + SUBTEST(live_forcewake_ops), |
---|
| 330 | + SUBTEST(live_forcewake_domains), |
---|
| 331 | + }; |
---|
183 | 332 | |
---|
184 | | - /* Confirm the table we load is still valid */ |
---|
185 | | - err = intel_fw_table_check(i915->uncore.fw_domains_table, |
---|
186 | | - i915->uncore.fw_domains_table_entries, |
---|
187 | | - INTEL_GEN(i915) >= 9); |
---|
188 | | - if (err) |
---|
189 | | - return err; |
---|
190 | | - |
---|
191 | | - err = intel_uncore_check_forcewake_domains(i915); |
---|
192 | | - if (err) |
---|
193 | | - return err; |
---|
194 | | - |
---|
195 | | - return 0; |
---|
| 333 | + return intel_gt_live_subtests(tests, &i915->gt); |
---|
196 | 334 | } |
---|