]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/xe/pxp: Handle the PXP termination interrupt
authorDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Wed, 29 Jan 2025 17:41:29 +0000 (09:41 -0800)
committerDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Mon, 3 Feb 2025 19:51:13 +0000 (11:51 -0800)
When something happen to the session, the HW generates a termination
interrupt. In reply to this, the driver is required to submit an inline
session termination via the VCS, trigger the global termination and
notify the GSC FW that the session is now invalid.

v2: rename ARB define to make it cleaner to move it to uapi (John)
v3: fix parameter name in documentation

Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: John Harrison <John.C.Harrison@Intel.com>
Reviewed-by: John Harrison <John.C.Harrison@Intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20250129174140.948829-6-daniele.ceraolospurio@intel.com
drivers/gpu/drm/xe/regs/xe_irq_regs.h
drivers/gpu/drm/xe/regs/xe_pxp_regs.h
drivers/gpu/drm/xe/xe_irq.c
drivers/gpu/drm/xe/xe_pxp.c
drivers/gpu/drm/xe/xe_pxp.h
drivers/gpu/drm/xe/xe_pxp_types.h

index 1776b3f78ccb74082ed97b6bd11352e687aa9d44..f0ecfcac40037828e3123e2ad8140bb1085180ea 100644 (file)
@@ -44,6 +44,7 @@
 #define   ENGINE1_MASK                         REG_GENMASK(31, 16)
 #define   ENGINE0_MASK                         REG_GENMASK(15, 0)
 #define GPM_WGBOXPERF_INTR_ENABLE              XE_REG(0x19003c, XE_REG_OPTION_VF)
+#define CRYPTO_RSVD_INTR_ENABLE                        XE_REG(0x190040)
 #define GUNIT_GSC_INTR_ENABLE                  XE_REG(0x190044, XE_REG_OPTION_VF)
 #define CCS_RSVD_INTR_ENABLE                   XE_REG(0x190048, XE_REG_OPTION_VF)
 
@@ -54,6 +55,7 @@
 #define   INTR_ENGINE_INTR(x)                  REG_FIELD_GET(GENMASK(15, 0), x)
 #define   OTHER_GUC_INSTANCE                   0
 #define   OTHER_GSC_HECI2_INSTANCE             3
+#define   OTHER_KCR_INSTANCE                   4
 #define   OTHER_GSC_INSTANCE                   6
 
 #define IIR_REG_SELECTOR(x)                    XE_REG(0x190070 + ((x) * 4), XE_REG_OPTION_VF)
@@ -65,6 +67,7 @@
 #define HECI2_RSVD_INTR_MASK                   XE_REG(0x1900e4)
 #define GUC_SG_INTR_MASK                       XE_REG(0x1900e8, XE_REG_OPTION_VF)
 #define GPM_WGBOXPERF_INTR_MASK                        XE_REG(0x1900ec, XE_REG_OPTION_VF)
+#define CRYPTO_RSVD_INTR_MASK                  XE_REG(0x1900f0)
 #define GUNIT_GSC_INTR_MASK                    XE_REG(0x1900f4, XE_REG_OPTION_VF)
 #define CCS0_CCS1_INTR_MASK                    XE_REG(0x190100)
 #define CCS2_CCS3_INTR_MASK                    XE_REG(0x190104)
@@ -79,4 +82,9 @@
 #define   GT_CS_MASTER_ERROR_INTERRUPT         REG_BIT(3)
 #define   GT_RENDER_USER_INTERRUPT             REG_BIT(0)
 
+/* irqs for OTHER_KCR_INSTANCE */
+#define   KCR_PXP_STATE_TERMINATED_INTERRUPT           REG_BIT(1)
+#define   KCR_APP_TERMINATED_PER_FW_REQ_INTERRUPT      REG_BIT(2)
+#define   KCR_PXP_STATE_RESET_COMPLETE_INTERRUPT       REG_BIT(3)
+
 #endif
index d67cf210d23d56845133ae3f0359a6e16d4282cc..aa158938b42eb730e6e47b290fb03850568a5203 100644 (file)
 #define KCR_INIT                               XE_REG(0x3860f0)
 #define   KCR_INIT_ALLOW_DISPLAY_ME_WRITES     REG_BIT(14)
 
+/* KCR hwdrm session in play status 0-31 */
+#define KCR_SIP                                        XE_REG(0x386260)
+
+/* PXP global terminate register for session termination */
+#define KCR_GLOBAL_TERMINATE                   XE_REG(0x3860f8)
+
 #endif /* __XE_PXP_REGS_H__ */
index 32f5a67a917b5828d6295647ff5811cb89723439..bf092e6391c7dc23e0f9f2fac46daea4db6ab334 100644 (file)
@@ -20,6 +20,7 @@
 #include "xe_hw_engine.h"
 #include "xe_memirq.h"
 #include "xe_mmio.h"
+#include "xe_pxp.h"
 #include "xe_sriov.h"
 
 /*
@@ -208,6 +209,15 @@ void xe_irq_enable_hwe(struct xe_gt *gt)
                }
                if (heci_mask)
                        xe_mmio_write32(mmio, HECI2_RSVD_INTR_MASK, ~(heci_mask << 16));
+
+               if (xe_pxp_is_supported(xe)) {
+                       u32 kcr_mask = KCR_PXP_STATE_TERMINATED_INTERRUPT |
+                                      KCR_APP_TERMINATED_PER_FW_REQ_INTERRUPT |
+                                      KCR_PXP_STATE_RESET_COMPLETE_INTERRUPT;
+
+                       xe_mmio_write32(mmio, CRYPTO_RSVD_INTR_ENABLE, kcr_mask << 16);
+                       xe_mmio_write32(mmio, CRYPTO_RSVD_INTR_MASK, ~(kcr_mask << 16));
+               }
        }
 }
 
@@ -330,9 +340,15 @@ static void gt_irq_handler(struct xe_tile *tile,
                        }
 
                        if (class == XE_ENGINE_CLASS_OTHER) {
-                               /* HECI GSCFI interrupts come from outside of GT */
+                               /*
+                                * HECI GSCFI interrupts come from outside of GT.
+                                * KCR irqs come from inside GT but are handled
+                                * by the global PXP subsystem.
+                                */
                                if (xe->info.has_heci_gscfi && instance == OTHER_GSC_INSTANCE)
                                        xe_heci_gsc_irq_handler(xe, intr_vec);
+                               else if (instance == OTHER_KCR_INSTANCE)
+                                       xe_pxp_irq_handler(xe, intr_vec);
                                else
                                        gt_other_irq_handler(engine_gt, instance, intr_vec);
                        }
@@ -510,6 +526,8 @@ static void gt_irq_reset(struct xe_tile *tile)
                xe_mmio_write32(mmio, GUNIT_GSC_INTR_ENABLE, 0);
                xe_mmio_write32(mmio, GUNIT_GSC_INTR_MASK, ~0);
                xe_mmio_write32(mmio, HECI2_RSVD_INTR_MASK, ~0);
+               xe_mmio_write32(mmio, CRYPTO_RSVD_INTR_ENABLE, 0);
+               xe_mmio_write32(mmio, CRYPTO_RSVD_INTR_MASK, ~0);
        }
 
        xe_mmio_write32(mmio, GPM_WGBOXPERF_INTR_ENABLE, 0);
index 89d71a69cdff4e7ecfb87cdd1b396bc6f521ab37..1452a4763ac2d19a05306a9f884ad083186ee6b6 100644 (file)
 #include "xe_gt.h"
 #include "xe_gt_types.h"
 #include "xe_mmio.h"
+#include "xe_pm.h"
 #include "xe_pxp_submit.h"
 #include "xe_pxp_types.h"
 #include "xe_uc_fw.h"
+#include "regs/xe_irq_regs.h"
 #include "regs/xe_pxp_regs.h"
 
 /**
  * integrated parts.
  */
 
-static bool pxp_is_supported(const struct xe_device *xe)
+#define ARB_SESSION DRM_XE_PXP_HWDRM_DEFAULT_SESSION /* shorter define */
+
+bool xe_pxp_is_supported(const struct xe_device *xe)
 {
        return xe->info.has_pxp && IS_ENABLED(CONFIG_INTEL_MEI_GSC_PROXY);
 }
 
+static bool pxp_is_enabled(const struct xe_pxp *pxp)
+{
+       return pxp;
+}
+
+static int pxp_wait_for_session_state(struct xe_pxp *pxp, u32 id, bool in_play)
+{
+       struct xe_gt *gt = pxp->gt;
+       u32 mask = BIT(id);
+
+       return xe_mmio_wait32(&gt->mmio, KCR_SIP, mask, in_play ? mask : 0,
+                             250, NULL, false);
+}
+
+static void pxp_terminate(struct xe_pxp *pxp)
+{
+       int ret = 0;
+       struct xe_device *xe = pxp->xe;
+       struct xe_gt *gt = pxp->gt;
+       unsigned int fw_ref;
+
+       drm_dbg(&xe->drm, "Terminating PXP\n");
+
+       fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT);
+       if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) {
+               ret = -EIO;
+               goto out;
+       }
+
+       /* terminate the hw session */
+       ret = xe_pxp_submit_session_termination(pxp, ARB_SESSION);
+       if (ret)
+               goto out;
+
+       ret = pxp_wait_for_session_state(pxp, ARB_SESSION, false);
+       if (ret)
+               goto out;
+
+       /* Trigger full HW cleanup */
+       xe_mmio_write32(&gt->mmio, KCR_GLOBAL_TERMINATE, 1);
+
+       /* now we can tell the GSC to clean up its own state */
+       ret = xe_pxp_submit_session_invalidation(&pxp->gsc_res, ARB_SESSION);
+
+out:
+       xe_force_wake_put(gt_to_fw(gt), fw_ref);
+
+       if (ret)
+               drm_err(&xe->drm, "PXP termination failed: %pe\n", ERR_PTR(ret));
+}
+
+static void pxp_terminate_complete(struct xe_pxp *pxp)
+{
+       /* TODO mark the session as ready to start */
+}
+
+static void pxp_irq_work(struct work_struct *work)
+{
+       struct xe_pxp *pxp = container_of(work, typeof(*pxp), irq.work);
+       struct xe_device *xe = pxp->xe;
+       u32 events = 0;
+
+       spin_lock_irq(&xe->irq.lock);
+       events = pxp->irq.events;
+       pxp->irq.events = 0;
+       spin_unlock_irq(&xe->irq.lock);
+
+       if (!events)
+               return;
+
+       /*
+        * If we're processing a termination irq while suspending then don't
+        * bother, we're going to re-init everything on resume anyway.
+        */
+       if ((events & PXP_TERMINATION_REQUEST) && !xe_pm_runtime_get_if_active(xe))
+               return;
+
+       if (events & PXP_TERMINATION_REQUEST) {
+               events &= ~PXP_TERMINATION_COMPLETE;
+               pxp_terminate(pxp);
+       }
+
+       if (events & PXP_TERMINATION_COMPLETE)
+               pxp_terminate_complete(pxp);
+
+       if (events & PXP_TERMINATION_REQUEST)
+               xe_pm_runtime_put(xe);
+}
+
+/**
+ * xe_pxp_irq_handler - Handles PXP interrupts.
+ * @xe: the xe_device structure
+ * @iir: interrupt vector
+ */
+void xe_pxp_irq_handler(struct xe_device *xe, u16 iir)
+{
+       struct xe_pxp *pxp = xe->pxp;
+
+       if (!pxp_is_enabled(pxp)) {
+               drm_err(&xe->drm, "PXP irq 0x%x received with PXP disabled!\n", iir);
+               return;
+       }
+
+       lockdep_assert_held(&xe->irq.lock);
+
+       if (unlikely(!iir))
+               return;
+
+       if (iir & (KCR_PXP_STATE_TERMINATED_INTERRUPT |
+                  KCR_APP_TERMINATED_PER_FW_REQ_INTERRUPT))
+               pxp->irq.events |= PXP_TERMINATION_REQUEST;
+
+       if (iir & KCR_PXP_STATE_RESET_COMPLETE_INTERRUPT)
+               pxp->irq.events |= PXP_TERMINATION_COMPLETE;
+
+       if (pxp->irq.events)
+               queue_work(pxp->irq.wq, &pxp->irq.work);
+}
+
 static int kcr_pxp_set_status(const struct xe_pxp *pxp, bool enable)
 {
        u32 val = enable ? _MASKED_BIT_ENABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES) :
@@ -60,6 +183,7 @@ static void pxp_fini(void *arg)
 {
        struct xe_pxp *pxp = arg;
 
+       destroy_workqueue(pxp->irq.wq);
        xe_pxp_destroy_execution_resources(pxp);
 
        /* no need to explicitly disable KCR since we're going to do an FLR */
@@ -83,7 +207,7 @@ int xe_pxp_init(struct xe_device *xe)
        struct xe_pxp *pxp;
        int err;
 
-       if (!pxp_is_supported(xe))
+       if (!xe_pxp_is_supported(xe))
                return -EOPNOTSUPP;
 
        /* we only support PXP on single tile devices with a media GT */
@@ -105,12 +229,19 @@ int xe_pxp_init(struct xe_device *xe)
        if (!pxp)
                return -ENOMEM;
 
+       INIT_WORK(&pxp->irq.work, pxp_irq_work);
        pxp->xe = xe;
        pxp->gt = gt;
 
+       pxp->irq.wq = alloc_ordered_workqueue("pxp-wq", 0);
+       if (!pxp->irq.wq) {
+               err = -ENOMEM;
+               goto out_free;
+       }
+
        err = kcr_pxp_enable(pxp);
        if (err)
-               goto out_free;
+               goto out_wq;
 
        err = xe_pxp_allocate_execution_resources(pxp);
        if (err)
@@ -122,6 +253,8 @@ int xe_pxp_init(struct xe_device *xe)
 
 out_kcr_disable:
        kcr_pxp_disable(pxp);
+out_wq:
+       destroy_workqueue(pxp->irq.wq);
 out_free:
        drmm_kfree(&xe->drm, pxp);
        return err;
index 00f5e688c0d913954c27d1478b75313051e507b8..39435c644dcdacb80052a901a4f5b3902a92eebf 100644 (file)
@@ -6,8 +6,15 @@
 #ifndef __XE_PXP_H__
 #define __XE_PXP_H__
 
+#include <linux/types.h>
+
 struct xe_device;
 
+#define DRM_XE_PXP_HWDRM_DEFAULT_SESSION 0xF /* TODO: move to uapi */
+
+bool xe_pxp_is_supported(const struct xe_device *xe);
+
 int xe_pxp_init(struct xe_device *xe);
+void xe_pxp_irq_handler(struct xe_device *xe, u16 iir);
 
 #endif /* __XE_PXP_H__ */
index 0f86b50756cceabaa36898b4e7760a1c33001d91..311d08111b5fafb22130c8c82c6fea9ddf4833c8 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/iosys-map.h>
 #include <linux/types.h>
+#include <linux/workqueue.h>
 
 struct xe_bo;
 struct xe_exec_queue;
@@ -69,6 +70,18 @@ struct xe_pxp {
 
        /** @gsc_res: kernel-owned objects for PXP submissions to the GSCCS */
        struct xe_pxp_gsc_client_resources gsc_res;
+
+       /** @irq: wrapper for the worker and queue used for PXP irq support */
+       struct {
+               /** @irq.work: worker that manages irq events. */
+               struct work_struct work;
+               /** @irq.wq: workqueue on which to queue the irq work. */
+               struct workqueue_struct *wq;
+               /** @irq.events: pending events, protected with xe->irq.lock. */
+               u32 events;
+#define PXP_TERMINATION_REQUEST  BIT(0)
+#define PXP_TERMINATION_COMPLETE BIT(1)
+       } irq;
 };
 
 #endif /* __XE_PXP_TYPES_H__ */