#include "i915_drv.h"
 #include "i915_trace.h"
+#include "intel_breadcrumbs.h"
 #include "intel_gt_pm.h"
 #include "intel_gt_requests.h"
 
 
 static void __intel_breadcrumbs_disarm_irq(struct intel_breadcrumbs *b)
 {
-       struct intel_engine_cs *engine =
-               container_of(b, struct intel_engine_cs, breadcrumbs);
-
        lockdep_assert_held(&b->irq_lock);
 
+       if (!b->irq_engine || !b->irq_armed)
+               return;
+
        GEM_BUG_ON(!b->irq_enabled);
        if (!--b->irq_enabled)
-               irq_disable(engine);
+               irq_disable(b->irq_engine);
 
        WRITE_ONCE(b->irq_armed, false);
-       intel_gt_pm_put_async(engine->gt);
+       intel_gt_pm_put_async(b->irq_engine->gt);
 }
 
-void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine)
+void intel_breadcrumbs_park(struct intel_breadcrumbs *b)
 {
-       struct intel_breadcrumbs *b = &engine->breadcrumbs;
        unsigned long flags;
 
        if (!READ_ONCE(b->irq_armed))
                return;
 
        spin_lock_irqsave(&b->irq_lock, flags);
-       if (b->irq_armed)
-               __intel_breadcrumbs_disarm_irq(b);
+       __intel_breadcrumbs_disarm_irq(b);
        spin_unlock_irqrestore(&b->irq_lock, flags);
 }
 
 
 static void add_retire(struct intel_breadcrumbs *b, struct intel_timeline *tl)
 {
-       struct intel_engine_cs *engine =
-               container_of(b, struct intel_engine_cs, breadcrumbs);
-
-       if (unlikely(intel_engine_is_virtual(engine)))
-               engine = intel_virtual_engine_get_sibling(engine, 0);
-
-       intel_engine_add_retire(engine, tl);
+       if (b->irq_engine)
+               intel_engine_add_retire(b->irq_engine, tl);
 }
 
 static bool __signal_request(struct i915_request *rq, struct list_head *signals)
 
        spin_lock(&b->irq_lock);
 
-       if (b->irq_armed && list_empty(&b->signalers))
+       if (list_empty(&b->signalers))
                __intel_breadcrumbs_disarm_irq(b);
 
        list_splice_init(&b->signaled_requests, &signal);
 
 static void __intel_breadcrumbs_arm_irq(struct intel_breadcrumbs *b)
 {
-       struct intel_engine_cs *engine =
-               container_of(b, struct intel_engine_cs, breadcrumbs);
-
        lockdep_assert_held(&b->irq_lock);
-       if (b->irq_armed)
+
+       if (!b->irq_engine || b->irq_armed)
                return;
 
-       if (!intel_gt_pm_get_if_awake(engine->gt))
+       if (!intel_gt_pm_get_if_awake(b->irq_engine->gt))
                return;
 
        /*
         */
 
        if (!b->irq_enabled++)
-               irq_enable(engine);
+               irq_enable(b->irq_engine);
 }
 
-void intel_engine_init_breadcrumbs(struct intel_engine_cs *engine)
+struct intel_breadcrumbs *
+intel_breadcrumbs_create(struct intel_engine_cs *irq_engine)
 {
-       struct intel_breadcrumbs *b = &engine->breadcrumbs;
+       struct intel_breadcrumbs *b;
+
+       b = kzalloc(sizeof(*b), GFP_KERNEL);
+       if (!b)
+               return NULL;
 
        spin_lock_init(&b->irq_lock);
        INIT_LIST_HEAD(&b->signalers);
        INIT_LIST_HEAD(&b->signaled_requests);
 
        init_irq_work(&b->irq_work, signal_irq_work);
+
+       b->irq_engine = irq_engine;
+
+       return b;
 }
 
-void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine)
+void intel_breadcrumbs_reset(struct intel_breadcrumbs *b)
 {
-       struct intel_breadcrumbs *b = &engine->breadcrumbs;
        unsigned long flags;
 
+       if (!b->irq_engine)
+               return;
+
        spin_lock_irqsave(&b->irq_lock, flags);
 
        if (b->irq_enabled)
-               irq_enable(engine);
+               irq_enable(b->irq_engine);
        else
-               irq_disable(engine);
+               irq_disable(b->irq_engine);
 
        spin_unlock_irqrestore(&b->irq_lock, flags);
 }
 
-void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine)
+void intel_breadcrumbs_free(struct intel_breadcrumbs *b)
 {
+       kfree(b);
 }
 
 static void insert_breadcrumb(struct i915_request *rq,
         * request submit/unsubmit path, and so we must be more careful to
         * acquire the right lock.
         */
-       b = &READ_ONCE(rq->engine)->breadcrumbs;
+       b = READ_ONCE(rq->engine)->breadcrumbs;
        spin_lock(&b->irq_lock);
-       while (unlikely(b != &READ_ONCE(rq->engine)->breadcrumbs)) {
+       while (unlikely(b != READ_ONCE(rq->engine)->breadcrumbs)) {
                spin_unlock(&b->irq_lock);
-               b = &READ_ONCE(rq->engine)->breadcrumbs;
+               b = READ_ONCE(rq->engine)->breadcrumbs;
                spin_lock(&b->irq_lock);
        }
 
 
 void i915_request_cancel_breadcrumb(struct i915_request *rq)
 {
-       struct intel_breadcrumbs *b = &rq->engine->breadcrumbs;
+       struct intel_breadcrumbs *b = rq->engine->breadcrumbs;
 
        /*
         * We must wait for b->irq_lock so that we know the interrupt handler
 void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
                                    struct drm_printer *p)
 {
-       struct intel_breadcrumbs *b = &engine->breadcrumbs;
+       struct intel_breadcrumbs *b = engine->breadcrumbs;
        struct intel_context *ce;
        struct i915_request *rq;
 
-       if (list_empty(&b->signalers))
+       if (!b || list_empty(&b->signalers))
                return;
 
        drm_printf(p, "Signals:\n");
 
--- /dev/null
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_BREADCRUMBS__
+#define __INTEL_BREADCRUMBS__
+
+#include <linux/irq_work.h>
+
+#include "intel_engine_types.h"
+
+struct drm_printer;
+struct i915_request;
+struct intel_breadcrumbs;
+
+struct intel_breadcrumbs *
+intel_breadcrumbs_create(struct intel_engine_cs *irq_engine);
+void intel_breadcrumbs_free(struct intel_breadcrumbs *b);
+
+void intel_breadcrumbs_reset(struct intel_breadcrumbs *b);
+void intel_breadcrumbs_park(struct intel_breadcrumbs *b);
+
+static inline void
+intel_engine_signal_breadcrumbs(struct intel_engine_cs *engine)
+{
+       irq_work_queue(&engine->breadcrumbs->irq_work);
+}
+
+void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
+                                   struct drm_printer *p);
+
+bool i915_request_enable_breadcrumb(struct i915_request *request);
+void i915_request_cancel_breadcrumb(struct i915_request *request);
+
+#endif /* __INTEL_BREADCRUMBS__ */
 
--- /dev/null
+/* SPDX-License-Identifier: MIT */
+/*
+ * Copyright © 2019 Intel Corporation
+ */
+
+#ifndef __INTEL_BREADCRUMBS_TYPES__
+#define __INTEL_BREADCRUMBS_TYPES__
+
+#include <linux/irq_work.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+/*
+ * Rather than have every client wait upon all user interrupts,
+ * with the herd waking after every interrupt and each doing the
+ * heavyweight seqno dance, we delegate the task (of being the
+ * bottom-half of the user interrupt) to the first client. After
+ * every interrupt, we wake up one client, who does the heavyweight
+ * coherent seqno read and either goes back to sleep (if incomplete),
+ * or wakes up all the completed clients in parallel, before then
+ * transferring the bottom-half status to the next client in the queue.
+ *
+ * Compared to walking the entire list of waiters in a single dedicated
+ * bottom-half, we reduce the latency of the first waiter by avoiding
+ * a context switch, but incur additional coherent seqno reads when
+ * following the chain of request breadcrumbs. Since it is most likely
+ * that we have a single client waiting on each seqno, then reducing
+ * the overhead of waking that client is much preferred.
+ */
+struct intel_breadcrumbs {
+       spinlock_t irq_lock; /* protects the lists used in hardirq context */
+
+       /* Not all breadcrumbs are attached to physical HW */
+       struct intel_engine_cs *irq_engine;
+
+       struct list_head signalers;
+       struct list_head signaled_requests;
+
+       struct irq_work irq_work; /* for use from inside irq_lock */
+
+       unsigned int irq_enabled;
+
+       bool irq_armed;
+};
+
+#endif /* __INTEL_BREADCRUMBS_TYPES__ */
 
 
 void intel_engine_init_execlists(struct intel_engine_cs *engine);
 
-void intel_engine_init_breadcrumbs(struct intel_engine_cs *engine);
-void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
-
-void intel_engine_disarm_breadcrumbs(struct intel_engine_cs *engine);
-
-static inline void
-intel_engine_signal_breadcrumbs(struct intel_engine_cs *engine)
-{
-       irq_work_queue(&engine->breadcrumbs.irq_work);
-}
-
-void intel_engine_reset_breadcrumbs(struct intel_engine_cs *engine);
-void intel_engine_fini_breadcrumbs(struct intel_engine_cs *engine);
-
-void intel_engine_print_breadcrumbs(struct intel_engine_cs *engine,
-                                   struct drm_printer *p);
-
 static inline u32 *__gen8_emit_pipe_control(u32 *batch, u32 flags0, u32 flags1, u32 offset)
 {
        memset(batch, 0, 6 * sizeof(u32));
 
 
 #include "i915_drv.h"
 
+#include "intel_breadcrumbs.h"
 #include "intel_context.h"
 #include "intel_engine.h"
 #include "intel_engine_pm.h"
        if (err)
                return err;
 
+       engine->breadcrumbs = intel_breadcrumbs_create(engine);
+       if (!engine->breadcrumbs) {
+               err = -ENOMEM;
+               goto err_status;
+       }
+
        intel_engine_init_active(engine, ENGINE_PHYSICAL);
-       intel_engine_init_breadcrumbs(engine);
        intel_engine_init_execlists(engine);
        intel_engine_init_cmd_parser(engine);
        intel_engine_init__pm(engine);
        intel_engine_init_ctx_wa(engine);
 
        return 0;
+
+err_status:
+       cleanup_status_page(engine);
+       return err;
 }
 
 struct measure_breadcrumb {
        tasklet_kill(&engine->execlists.tasklet); /* flush the callback */
 
        cleanup_status_page(engine);
+       intel_breadcrumbs_free(engine->breadcrumbs);
 
        intel_engine_fini_retire(engine);
-       intel_engine_fini_breadcrumbs(engine);
        intel_engine_cleanup_cmd_parser(engine);
 
        if (engine->default_state)
 
 
 #include "i915_drv.h"
 
+#include "intel_breadcrumbs.h"
 #include "intel_context.h"
 #include "intel_engine.h"
 #include "intel_engine_heartbeat.h"
        call_idle_barriers(engine); /* cleanup after wedging */
 
        intel_engine_park_heartbeat(engine);
-       intel_engine_disarm_breadcrumbs(engine);
+       intel_breadcrumbs_park(engine->breadcrumbs);
 
        /* Must be reset upon idling, or we may miss the busy wakeup. */
        GEM_BUG_ON(engine->execlists.queue_priority_hint != INT_MIN);
 
 #include "i915_pmu.h"
 #include "i915_priolist_types.h"
 #include "i915_selftest.h"
+#include "intel_breadcrumbs_types.h"
 #include "intel_sseu.h"
 #include "intel_timeline_types.h"
 #include "intel_uncore.h"
         */
        struct ewma__engine_latency latency;
 
-       /* Rather than have every client wait upon all user interrupts,
-        * with the herd waking after every interrupt and each doing the
-        * heavyweight seqno dance, we delegate the task (of being the
-        * bottom-half of the user interrupt) to the first client. After
-        * every interrupt, we wake up one client, who does the heavyweight
-        * coherent seqno read and either goes back to sleep (if incomplete),
-        * or wakes up all the completed clients in parallel, before then
-        * transferring the bottom-half status to the next client in the queue.
-        *
-        * Compared to walking the entire list of waiters in a single dedicated
-        * bottom-half, we reduce the latency of the first waiter by avoiding
-        * a context switch, but incur additional coherent seqno reads when
-        * following the chain of request breadcrumbs. Since it is most likely
-        * that we have a single client waiting on each seqno, then reducing
-        * the overhead of waking that client is much preferred.
-        */
-       struct intel_breadcrumbs {
-               spinlock_t irq_lock;
-               struct list_head signalers;
-
-               struct list_head signaled_requests;
-
-               struct irq_work irq_work; /* for use from inside irq_lock */
-
-               unsigned int irq_enabled;
-
-               bool irq_armed;
-       } breadcrumbs;
+       /* Keep track of all the seqno used, a trail of breadcrumbs */
+       struct intel_breadcrumbs *breadcrumbs;
 
        struct intel_engine_pmu {
                /**
 
 
 #include "i915_drv.h"
 #include "i915_irq.h"
+#include "intel_breadcrumbs.h"
 #include "intel_gt.h"
 #include "intel_gt_irq.h"
 #include "intel_uncore.h"
 
 #include "i915_perf.h"
 #include "i915_trace.h"
 #include "i915_vgpu.h"
+#include "intel_breadcrumbs.h"
 #include "intel_context.h"
 #include "intel_engine_pm.h"
 #include "intel_gt.h"
 {
        intel_mocs_init_engine(engine);
 
-       intel_engine_reset_breadcrumbs(engine);
+       intel_breadcrumbs_reset(engine->breadcrumbs);
 
        if (GEM_SHOW_DEBUG() && unexpected_starting_state(engine)) {
                struct drm_printer p = drm_debug_printer(__func__);
        snprintf(ve->base.name, sizeof(ve->base.name), "virtual");
 
        intel_engine_init_active(&ve->base, ENGINE_VIRTUAL);
-       intel_engine_init_breadcrumbs(&ve->base);
        intel_engine_init_execlists(&ve->base);
-       ve->base.breadcrumbs.irq_armed = true; /* fake HW, used for irq_work */
 
        ve->base.cops = &virtual_context_ops;
        ve->base.request_alloc = execlists_request_alloc;
 
        intel_context_init(&ve->context, &ve->base);
 
+       ve->base.breadcrumbs = intel_breadcrumbs_create(NULL);
+       if (!ve->base.breadcrumbs) {
+               err = -ENOMEM;
+               goto err_put;
+       }
+
        for (n = 0; n < count; n++) {
                struct intel_engine_cs *sibling = siblings[n];
 
 
 #include "i915_drv.h"
 #include "i915_gpu_error.h"
 #include "i915_irq.h"
+#include "intel_breadcrumbs.h"
 #include "intel_engine_pm.h"
 #include "intel_gt.h"
 #include "intel_gt_pm.h"
 
 #include "gen6_ppgtt.h"
 #include "gen7_renderclear.h"
 #include "i915_drv.h"
+#include "intel_breadcrumbs.h"
 #include "intel_context.h"
 #include "intel_gt.h"
 #include "intel_reset.h"
        else
                ring_setup_status_page(engine);
 
-       intel_engine_reset_breadcrumbs(engine);
+       intel_breadcrumbs_reset(engine->breadcrumbs);
 
        /* Enforce ordering by reading HEAD register back */
        ENGINE_POSTING_READ(engine, RING_HEAD);
 
 #include <drm/i915_drm.h>
 
 #include "i915_drv.h"
+#include "intel_breadcrumbs.h"
 #include "intel_gt.h"
 #include "intel_gt_clock_utils.h"
 #include "intel_gt_irq.h"
 
 
        GEM_BUG_ON(timer_pending(&mock->hw_delay));
 
+       intel_breadcrumbs_free(engine->breadcrumbs);
+
        intel_context_unpin(engine->kernel_context);
        intel_context_put(engine->kernel_context);
 
        intel_engine_fini_retire(engine);
-       intel_engine_fini_breadcrumbs(engine);
 }
 
 struct intel_engine_cs *mock_engine(struct drm_i915_private *i915,
        struct intel_context *ce;
 
        intel_engine_init_active(engine, ENGINE_MOCK);
-       intel_engine_init_breadcrumbs(engine);
        intel_engine_init_execlists(engine);
        intel_engine_init__pm(engine);
        intel_engine_init_retire(engine);
 
+       engine->breadcrumbs = intel_breadcrumbs_create(NULL);
+       if (!engine->breadcrumbs)
+               return -ENOMEM;
+
        ce = create_kernel_context(engine);
        if (IS_ERR(ce))
                goto err_breadcrumbs;
        return 0;
 
 err_breadcrumbs:
-       intel_engine_fini_breadcrumbs(engine);
+       intel_breadcrumbs_free(engine->breadcrumbs);
        return -ENOMEM;
 }
 
 
 #include "display/intel_lpe_audio.h"
 #include "display/intel_psr.h"
 
+#include "gt/intel_breadcrumbs.h"
 #include "gt/intel_gt.h"
 #include "gt/intel_gt_irq.h"
 #include "gt/intel_gt_pm_irq.h"
 
 #include <linux/sched/signal.h>
 
 #include "gem/i915_gem_context.h"
+#include "gt/intel_breadcrumbs.h"
 #include "gt/intel_context.h"
 #include "gt/intel_ring.h"
 #include "gt/intel_rps.h"
 
 void __i915_request_unsubmit(struct i915_request *request);
 void i915_request_unsubmit(struct i915_request *request);
 
-/* Note: part of the intel_breadcrumbs family */
-bool i915_request_enable_breadcrumb(struct i915_request *request);
-void i915_request_cancel_breadcrumb(struct i915_request *request);
-
 long i915_request_wait(struct i915_request *rq,
                       unsigned int flags,
                       long timeout)