Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/i915/guc: Direct all breadcrumbs for a class to single breadcrumbs

With GuC virtual engines the physical engine which a request executes
and completes on isn't known to the i915. Therefore we can't attach a
request to a physical engines breadcrumbs. To work around this we create
a single breadcrumbs per engine class when using GuC submission and
direct all physical engine interrupts to this breadcrumbs.

v2:
(John H)
- Rework header file structure so intel_engine_mask_t can be in
intel_engine_types.h

Signed-off-by: Matthew Brost <matthew.brost@intel.com>
CC: John Harrison <John.C.Harrison@Intel.com>
Reviewed-by: John Harrison <John.C.Harrison@Intel.com>
Signed-off-by: John Harrison <John.C.Harrison@Intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20210727002348.97202-6-matthew.brost@intel.com

authored by

Matthew Brost and committed by
John Harrison
a95d1160 b02d86b9

+133 -37
+17 -24
drivers/gpu/drm/i915/gt/intel_breadcrumbs.c
··· 15 15 #include "intel_gt_pm.h" 16 16 #include "intel_gt_requests.h" 17 17 18 - static bool irq_enable(struct intel_engine_cs *engine) 18 + static bool irq_enable(struct intel_breadcrumbs *b) 19 19 { 20 - if (!engine->irq_enable) 21 - return false; 22 - 23 - /* Caller disables interrupts */ 24 - spin_lock(&engine->gt->irq_lock); 25 - engine->irq_enable(engine); 26 - spin_unlock(&engine->gt->irq_lock); 27 - 28 - return true; 20 + return intel_engine_irq_enable(b->irq_engine); 29 21 } 30 22 31 - static void irq_disable(struct intel_engine_cs *engine) 23 + static void irq_disable(struct intel_breadcrumbs *b) 32 24 { 33 - if (!engine->irq_disable) 34 - return; 35 - 36 - /* Caller disables interrupts */ 37 - spin_lock(&engine->gt->irq_lock); 38 - engine->irq_disable(engine); 39 - spin_unlock(&engine->gt->irq_lock); 25 + intel_engine_irq_disable(b->irq_engine); 40 26 } 41 27 42 28 static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b) ··· 43 57 WRITE_ONCE(b->irq_armed, true); 44 58 45 59 /* Requests may have completed before we could enable the interrupt. */ 46 - if (!b->irq_enabled++ && irq_enable(b->irq_engine)) 60 + if (!b->irq_enabled++ && b->irq_enable(b)) 47 61 irq_work_queue(&b->irq_work); 48 62 } 49 63 ··· 62 76 { 63 77 GEM_BUG_ON(!b->irq_enabled); 64 78 if (!--b->irq_enabled) 65 - irq_disable(b->irq_engine); 79 + b->irq_disable(b); 66 80 67 81 WRITE_ONCE(b->irq_armed, false); 68 82 intel_gt_pm_put_async(b->irq_engine->gt); ··· 267 281 if (!b) 268 282 return NULL; 269 283 270 - b->irq_engine = irq_engine; 284 + kref_init(&b->ref); 271 285 272 286 spin_lock_init(&b->signalers_lock); 273 287 INIT_LIST_HEAD(&b->signalers); ··· 275 289 276 290 spin_lock_init(&b->irq_lock); 277 291 init_irq_work(&b->irq_work, signal_irq_work); 292 + 293 + b->irq_engine = irq_engine; 294 + b->irq_enable = irq_enable; 295 + b->irq_disable = irq_disable; 278 296 279 297 return b; 280 298 } ··· 293 303 spin_lock_irqsave(&b->irq_lock, flags); 294 304 295 305 if (b->irq_enabled) 296 - irq_enable(b->irq_engine); 306 + b->irq_enable(b); 297 307 else 298 - irq_disable(b->irq_engine); 308 + b->irq_disable(b); 299 309 300 310 spin_unlock_irqrestore(&b->irq_lock, flags); 301 311 } ··· 315 325 } 316 326 } 317 327 318 - void intel_breadcrumbs_free(struct intel_breadcrumbs *b) 328 + void intel_breadcrumbs_free(struct kref *kref) 319 329 { 330 + struct intel_breadcrumbs *b = container_of(kref, typeof(*b), ref); 331 + 320 332 irq_work_sync(&b->irq_work); 321 333 GEM_BUG_ON(!list_empty(&b->signalers)); 322 334 GEM_BUG_ON(b->irq_armed); 335 + 323 336 kfree(b); 324 337 } 325 338
+14 -2
drivers/gpu/drm/i915/gt/intel_breadcrumbs.h
··· 9 9 #include <linux/atomic.h> 10 10 #include <linux/irq_work.h> 11 11 12 - #include "intel_engine_types.h" 12 + #include "intel_breadcrumbs_types.h" 13 13 14 14 struct drm_printer; 15 15 struct i915_request; ··· 17 17 18 18 struct intel_breadcrumbs * 19 19 intel_breadcrumbs_create(struct intel_engine_cs *irq_engine); 20 - void intel_breadcrumbs_free(struct intel_breadcrumbs *b); 20 + void intel_breadcrumbs_free(struct kref *kref); 21 21 22 22 void intel_breadcrumbs_reset(struct intel_breadcrumbs *b); 23 23 void __intel_breadcrumbs_park(struct intel_breadcrumbs *b); ··· 47 47 48 48 void intel_context_remove_breadcrumbs(struct intel_context *ce, 49 49 struct intel_breadcrumbs *b); 50 + 51 + static inline struct intel_breadcrumbs * 52 + intel_breadcrumbs_get(struct intel_breadcrumbs *b) 53 + { 54 + kref_get(&b->ref); 55 + return b; 56 + } 57 + 58 + static inline void intel_breadcrumbs_put(struct intel_breadcrumbs *b) 59 + { 60 + kref_put(&b->ref, intel_breadcrumbs_free); 61 + } 50 62 51 63 #endif /* __INTEL_BREADCRUMBS__ */
+7
drivers/gpu/drm/i915/gt/intel_breadcrumbs_types.h
··· 7 7 #define __INTEL_BREADCRUMBS_TYPES__ 8 8 9 9 #include <linux/irq_work.h> 10 + #include <linux/kref.h> 10 11 #include <linux/list.h> 11 12 #include <linux/spinlock.h> 12 13 #include <linux/types.h> 14 + 15 + #include "intel_engine_types.h" 13 16 14 17 /* 15 18 * Rather than have every client wait upon all user interrupts, ··· 32 29 * the overhead of waking that client is much preferred. 33 30 */ 34 31 struct intel_breadcrumbs { 32 + struct kref ref; 35 33 atomic_t active; 36 34 37 35 spinlock_t signalers_lock; /* protects the list of signalers */ ··· 46 42 bool irq_armed; 47 43 48 44 /* Not all breadcrumbs are attached to physical HW */ 45 + intel_engine_mask_t engine_mask; 49 46 struct intel_engine_cs *irq_engine; 47 + bool (*irq_enable)(struct intel_breadcrumbs *b); 48 + void (*irq_disable)(struct intel_breadcrumbs *b); 50 49 }; 51 50 52 51 #endif /* __INTEL_BREADCRUMBS_TYPES__ */
+3
drivers/gpu/drm/i915/gt/intel_engine.h
··· 212 212 213 213 void intel_engine_init_execlists(struct intel_engine_cs *engine); 214 214 215 + bool intel_engine_irq_enable(struct intel_engine_cs *engine); 216 + void intel_engine_irq_disable(struct intel_engine_cs *engine); 217 + 215 218 static inline void __intel_engine_reset(struct intel_engine_cs *engine, 216 219 bool stalled) 217 220 {
+26 -2
drivers/gpu/drm/i915/gt/intel_engine_cs.c
··· 798 798 err_cmd_parser: 799 799 i915_sched_engine_put(engine->sched_engine); 800 800 err_sched_engine: 801 - intel_breadcrumbs_free(engine->breadcrumbs); 801 + intel_breadcrumbs_put(engine->breadcrumbs); 802 802 err_status: 803 803 cleanup_status_page(engine); 804 804 return err; ··· 1007 1007 GEM_BUG_ON(!list_empty(&engine->sched_engine->requests)); 1008 1008 1009 1009 i915_sched_engine_put(engine->sched_engine); 1010 - intel_breadcrumbs_free(engine->breadcrumbs); 1010 + intel_breadcrumbs_put(engine->breadcrumbs); 1011 1011 1012 1012 intel_engine_fini_retire(engine); 1013 1013 intel_engine_cleanup_cmd_parser(engine); ··· 1322 1322 } 1323 1323 1324 1324 return true; 1325 + } 1326 + 1327 + bool intel_engine_irq_enable(struct intel_engine_cs *engine) 1328 + { 1329 + if (!engine->irq_enable) 1330 + return false; 1331 + 1332 + /* Caller disables interrupts */ 1333 + spin_lock(&engine->gt->irq_lock); 1334 + engine->irq_enable(engine); 1335 + spin_unlock(&engine->gt->irq_lock); 1336 + 1337 + return true; 1338 + } 1339 + 1340 + void intel_engine_irq_disable(struct intel_engine_cs *engine) 1341 + { 1342 + if (!engine->irq_disable) 1343 + return; 1344 + 1345 + /* Caller disables interrupts */ 1346 + spin_lock(&engine->gt->irq_lock); 1347 + engine->irq_disable(engine); 1348 + spin_unlock(&engine->gt->irq_lock); 1325 1349 } 1326 1350 1327 1351 void intel_engines_reset_default_submission(struct intel_gt *gt)
+1 -1
drivers/gpu/drm/i915/gt/intel_engine_types.h
··· 21 21 #include "i915_pmu.h" 22 22 #include "i915_priolist_types.h" 23 23 #include "i915_selftest.h" 24 - #include "intel_breadcrumbs_types.h" 25 24 #include "intel_sseu.h" 26 25 #include "intel_timeline_types.h" 27 26 #include "intel_uncore.h" ··· 51 52 struct intel_gt; 52 53 struct intel_ring; 53 54 struct intel_uncore; 55 + struct intel_breadcrumbs; 54 56 55 57 typedef u32 intel_engine_mask_t; 56 58 #define ALL_ENGINES ((intel_engine_mask_t)~0ul)
+1 -1
drivers/gpu/drm/i915/gt/intel_execlists_submission.c
··· 3457 3457 intel_context_fini(&ve->context); 3458 3458 3459 3459 if (ve->base.breadcrumbs) 3460 - intel_breadcrumbs_free(ve->base.breadcrumbs); 3460 + intel_breadcrumbs_put(ve->base.breadcrumbs); 3461 3461 if (ve->base.sched_engine) 3462 3462 i915_sched_engine_put(ve->base.sched_engine); 3463 3463 intel_engine_free_request_pool(&ve->base);
+2 -2
drivers/gpu/drm/i915/gt/mock_engine.c
··· 284 284 GEM_BUG_ON(timer_pending(&mock->hw_delay)); 285 285 286 286 i915_sched_engine_put(engine->sched_engine); 287 - intel_breadcrumbs_free(engine->breadcrumbs); 287 + intel_breadcrumbs_put(engine->breadcrumbs); 288 288 289 289 intel_context_unpin(engine->kernel_context); 290 290 intel_context_put(engine->kernel_context); ··· 370 370 return 0; 371 371 372 372 err_breadcrumbs: 373 - intel_breadcrumbs_free(engine->breadcrumbs); 373 + intel_breadcrumbs_put(engine->breadcrumbs); 374 374 err_schedule: 375 375 i915_sched_engine_put(engine->sched_engine); 376 376 return -ENOMEM;
+62 -5
drivers/gpu/drm/i915/gt/uc/intel_guc_submission.c
··· 1087 1087 struct guc_virtual_engine *ve = 1088 1088 container_of(ce, typeof(*ve), context); 1089 1089 1090 + if (ve->base.breadcrumbs) 1091 + intel_breadcrumbs_put(ve->base.breadcrumbs); 1092 + 1090 1093 kfree(ve); 1091 1094 } else { 1092 1095 intel_context_free(ce); ··· 1381 1378 .get_sibling = guc_virtual_get_sibling, 1382 1379 }; 1383 1380 1381 + static bool 1382 + guc_irq_enable_breadcrumbs(struct intel_breadcrumbs *b) 1383 + { 1384 + struct intel_engine_cs *sibling; 1385 + intel_engine_mask_t tmp, mask = b->engine_mask; 1386 + bool result = false; 1387 + 1388 + for_each_engine_masked(sibling, b->irq_engine->gt, mask, tmp) 1389 + result |= intel_engine_irq_enable(sibling); 1390 + 1391 + return result; 1392 + } 1393 + 1394 + static void 1395 + guc_irq_disable_breadcrumbs(struct intel_breadcrumbs *b) 1396 + { 1397 + struct intel_engine_cs *sibling; 1398 + intel_engine_mask_t tmp, mask = b->engine_mask; 1399 + 1400 + for_each_engine_masked(sibling, b->irq_engine->gt, mask, tmp) 1401 + intel_engine_irq_disable(sibling); 1402 + } 1403 + 1404 + static void guc_init_breadcrumbs(struct intel_engine_cs *engine) 1405 + { 1406 + int i; 1407 + 1408 + /* 1409 + * In GuC submission mode we do not know which physical engine a request 1410 + * will be scheduled on, this creates a problem because the breadcrumb 1411 + * interrupt is per physical engine. To work around this we attach 1412 + * requests and direct all breadcrumb interrupts to the first instance 1413 + * of an engine per class. In addition all breadcrumb interrupts are 1414 + * enabled / disabled across an engine class in unison. 1415 + */ 1416 + for (i = 0; i < MAX_ENGINE_INSTANCE; ++i) { 1417 + struct intel_engine_cs *sibling = 1418 + engine->gt->engine_class[engine->class][i]; 1419 + 1420 + if (sibling) { 1421 + if (engine->breadcrumbs != sibling->breadcrumbs) { 1422 + intel_breadcrumbs_put(engine->breadcrumbs); 1423 + engine->breadcrumbs = 1424 + intel_breadcrumbs_get(sibling->breadcrumbs); 1425 + } 1426 + break; 1427 + } 1428 + } 1429 + 1430 + if (engine->breadcrumbs) { 1431 + engine->breadcrumbs->engine_mask |= engine->mask; 1432 + engine->breadcrumbs->irq_enable = guc_irq_enable_breadcrumbs; 1433 + engine->breadcrumbs->irq_disable = guc_irq_disable_breadcrumbs; 1434 + } 1435 + } 1436 + 1384 1437 static void sanitize_hwsp(struct intel_engine_cs *engine) 1385 1438 { 1386 1439 struct intel_timeline *tl; ··· 1649 1590 1650 1591 guc_default_vfuncs(engine); 1651 1592 guc_default_irqs(engine); 1593 + guc_init_breadcrumbs(engine); 1652 1594 1653 1595 if (engine->class == RENDER_CLASS) 1654 1596 rcs_submission_override(engine); ··· 1892 1832 ve->base.instance = I915_ENGINE_CLASS_INVALID_VIRTUAL; 1893 1833 ve->base.uabi_instance = I915_ENGINE_CLASS_INVALID_VIRTUAL; 1894 1834 ve->base.saturated = ALL_ENGINES; 1895 - ve->base.breadcrumbs = intel_breadcrumbs_create(&ve->base); 1896 - if (!ve->base.breadcrumbs) { 1897 - kfree(ve); 1898 - return ERR_PTR(-ENOMEM); 1899 - } 1900 1835 1901 1836 snprintf(ve->base.name, sizeof(ve->base.name), "virtual"); 1902 1837 ··· 1940 1885 sibling->emit_fini_breadcrumb; 1941 1886 ve->base.emit_fini_breadcrumb_dw = 1942 1887 sibling->emit_fini_breadcrumb_dw; 1888 + ve->base.breadcrumbs = 1889 + intel_breadcrumbs_get(sibling->breadcrumbs); 1943 1890 1944 1891 ve->base.flags |= sibling->flags; 1945 1892