]> git.hungrycats.org Git - linux/commitdiff
drm/xe: memirq infra changes for MSI-X
authorIlia Levi <ilia.levi@intel.com>
Wed, 18 Sep 2024 05:39:41 +0000 (08:39 +0300)
committerMichal Wajdeczko <michal.wajdeczko@intel.com>
Thu, 19 Sep 2024 08:14:20 +0000 (10:14 +0200)
When using MSI-X, hw engines report interrupt status and source to engine
instance 0. For this scenario, in order to differentiate between the
engines, we need to pass different status/source pointers in the LRC.

The requirements on those pointers are:
- Interrupt status should be 4KiB aligned
- Interrupt source should be 64 bytes aligned

To accommodate this, we duplicate the current memirq page layout -
allocating a page for each engine instance and pass this page in the LRC.
Note that the same page can be reused for different engine types.
For example, an LRC executing on CCS #x will have pointers to page #x,
and an LRC executing on BCS #x will have the same pointers. Thus, to
locate the proper page, the pointer accessors were modified to receive
the hw engine.

Signed-off-by: Ilia Levi <ilia.levi@intel.com>
Reviewed-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Signed-off-by: Michal Wajdeczko <michal.wajdeczko@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20240918053942.1331811-5-illevi@habana.ai
drivers/gpu/drm/xe/xe_device.h
drivers/gpu/drm/xe/xe_lrc.c
drivers/gpu/drm/xe/xe_memirq.c
drivers/gpu/drm/xe/xe_memirq.h
drivers/gpu/drm/xe/xe_memirq_types.h

index 11a63384d3a892dfb086dca54e3ec8b90af5601c..4c3f0ebe78a90f655748fc5a6e7926e7f9ef8486 100644 (file)
@@ -155,6 +155,12 @@ static inline bool xe_device_has_sriov(struct xe_device *xe)
        return xe->info.has_sriov;
 }
 
+static inline bool xe_device_has_msix(struct xe_device *xe)
+{
+       /* TODO: change this when MSI-X support is fully integrated */
+       return false;
+}
+
 static inline bool xe_device_has_memirq(struct xe_device *xe)
 {
        return GRAPHICS_VERx100(xe) >= 1250;
@@ -162,7 +168,7 @@ static inline bool xe_device_has_memirq(struct xe_device *xe)
 
 static inline bool xe_device_uses_memirq(struct xe_device *xe)
 {
-       return xe_device_has_memirq(xe) && IS_SRIOV_VF(xe);
+       return xe_device_has_memirq(xe) && (IS_SRIOV_VF(xe) || xe_device_has_msix(xe));
 }
 
 u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size);
index e40f48f4240f5b1aef63fb4db7e5a5bcc5188caa..f0976230012aad31fd57ca3b7cbbc6ccdbba7c63 100644 (file)
@@ -613,9 +613,9 @@ static void set_memory_based_intr(u32 *regs, struct xe_hw_engine *hwe)
        regs[CTX_LRI_INT_REPORT_PTR] = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(2) |
                                       MI_LRI_LRM_CS_MMIO | MI_LRI_FORCE_POSTED;
        regs[CTX_INT_STATUS_REPORT_REG] = RING_INT_STATUS_RPT_PTR(0).addr;
-       regs[CTX_INT_STATUS_REPORT_PTR] = xe_memirq_status_ptr(memirq);
+       regs[CTX_INT_STATUS_REPORT_PTR] = xe_memirq_status_ptr(memirq, hwe);
        regs[CTX_INT_SRC_REPORT_REG] = RING_INT_SRC_RPT_PTR(0).addr;
-       regs[CTX_INT_SRC_REPORT_PTR] = xe_memirq_source_ptr(memirq);
+       regs[CTX_INT_SRC_REPORT_PTR] = xe_memirq_source_ptr(memirq, hwe);
 }
 
 static int lrc_ring_mi_mode(struct xe_hw_engine *hwe)
index 8b12209d995a864eaec49f5c0ac0e3f9871fb598..ae4279a7f947eea64965062431c3c7f88ab113cd 100644 (file)
@@ -115,6 +115,44 @@ static const char *guc_name(struct xe_guc *guc)
  *            |           |
  *            |           |
  *            +-----------+
+ *
+ *
+ * MSI-X use case
+ *
+ * When using MSI-X, hw engines report interrupt status and source to engine
+ * instance 0. For this scenario, in order to differentiate between the
+ * engines, we need to pass different status/source pointers in the LRC.
+ *
+ * The requirements on those pointers are:
+ * - Interrupt status should be 4KiB aligned
+ * - Interrupt source should be 64 bytes aligned
+ *
+ * To accommodate this, we duplicate the memirq page layout above -
+ * allocating a page for each engine instance and pass this page in the LRC.
+ * Note that the same page can be reused for different engine types.
+ * For example, an LRC executing on CCS #x will have pointers to page #x,
+ * and an LRC executing on BCS #x will have the same pointers.
+ *
+ * ::
+ *
+ *   0x0000   +==============================+  <== page for instance 0 (BCS0, CCS0, etc.)
+ *            | Interrupt Status Report Page |
+ *   0x0400   +==============================+
+ *            | Interrupt Source Report Page |
+ *   0x0440   +==============================+
+ *            | Interrupt Enable Mask        |
+ *            +==============================+
+ *            | Not used                     |
+ *   0x1000   +==============================+  <== page for instance 1 (BCS1, CCS1, etc.)
+ *            | Interrupt Status Report Page |
+ *   0x1400   +==============================+
+ *            | Interrupt Source Report Page |
+ *   0x1440   +==============================+
+ *            | Not used                     |
+ *   0x2000   +==============================+  <== page for instance 2 (BCS2, CCS2, etc.)
+ *            | ...                          |
+ *            +==============================+
+ *
  */
 
 static void __release_xe_bo(struct drm_device *drm, void *arg)
@@ -124,18 +162,30 @@ static void __release_xe_bo(struct drm_device *drm, void *arg)
        xe_bo_unpin_map_no_vm(bo);
 }
 
+static inline bool hw_reports_to_instance_zero(struct xe_memirq *memirq)
+{
+       /*
+        * When the HW engines are configured to use MSI-X,
+        * they report interrupt status and source to the offset of
+        * engine instance 0.
+        */
+       return xe_device_has_msix(memirq_to_xe(memirq));
+}
+
 static int memirq_alloc_pages(struct xe_memirq *memirq)
 {
        struct xe_device *xe = memirq_to_xe(memirq);
        struct xe_tile *tile = memirq_to_tile(memirq);
+       size_t bo_size = hw_reports_to_instance_zero(memirq) ?
+               XE_HW_ENGINE_MAX_INSTANCE * SZ_4K : SZ_4K;
        struct xe_bo *bo;
        int err;
 
-       BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_SOURCE_OFFSET, SZ_64));
-       BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_STATUS_OFFSET, SZ_4K));
+       BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_SOURCE_OFFSET(0), SZ_64));
+       BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_STATUS_OFFSET(0), SZ_4K));
 
        /* XXX: convert to managed bo */
-       bo = xe_bo_create_pin_map(xe, tile, NULL, SZ_4K,
+       bo = xe_bo_create_pin_map(xe, tile, NULL, bo_size,
                                  ttm_bo_type_kernel,
                                  XE_BO_FLAG_SYSTEM |
                                  XE_BO_FLAG_GGTT |
@@ -150,19 +200,20 @@ static int memirq_alloc_pages(struct xe_memirq *memirq)
        memirq_assert(memirq, !xe_bo_is_vram(bo));
        memirq_assert(memirq, !memirq->bo);
 
-       iosys_map_memset(&bo->vmap, 0, 0, SZ_4K);
+       iosys_map_memset(&bo->vmap, 0, 0, bo_size);
 
        memirq->bo = bo;
-       memirq->source = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_SOURCE_OFFSET);
-       memirq->status = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_STATUS_OFFSET);
+       memirq->source = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_SOURCE_OFFSET(0));
+       memirq->status = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_STATUS_OFFSET(0));
        memirq->mask = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_ENABLE_OFFSET);
 
        memirq_assert(memirq, !memirq->source.is_iomem);
        memirq_assert(memirq, !memirq->status.is_iomem);
        memirq_assert(memirq, !memirq->mask.is_iomem);
 
-       memirq_debug(memirq, "page offsets: source %#x status %#x\n",
-                    xe_memirq_source_ptr(memirq), xe_memirq_status_ptr(memirq));
+       memirq_debug(memirq, "page offsets: bo %#x bo_size %zu source %#x status %#x\n",
+                    xe_bo_ggtt_addr(bo), bo_size, XE_MEMIRQ_SOURCE_OFFSET(0),
+                    XE_MEMIRQ_STATUS_OFFSET(0));
 
        return drmm_add_action_or_reset(&xe->drm, __release_xe_bo, memirq->bo);
 
@@ -213,35 +264,45 @@ int xe_memirq_init(struct xe_memirq *memirq)
 /**
  * xe_memirq_source_ptr - Get GGTT's offset of the `Interrupt Source Report Page`_.
  * @memirq: the &xe_memirq to query
+ * @hwe: the hw engine for which we want the report page
  *
  * Shall be called when `Memory Based Interrupts`_ are used
  * and xe_memirq_init() didn't fail.
  *
  * Return: GGTT's offset of the `Interrupt Source Report Page`_.
  */
-u32 xe_memirq_source_ptr(struct xe_memirq *memirq)
+u32 xe_memirq_source_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe)
 {
+       u16 instance;
+
        memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq)));
        memirq_assert(memirq, memirq->bo);
 
-       return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_SOURCE_OFFSET;
+       instance = hw_reports_to_instance_zero(memirq) ? hwe->instance : 0;
+
+       return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_SOURCE_OFFSET(instance);
 }
 
 /**
  * xe_memirq_status_ptr - Get GGTT's offset of the `Interrupt Status Report Page`_.
  * @memirq: the &xe_memirq to query
+ * @hwe: the hw engine for which we want the report page
  *
  * Shall be called when `Memory Based Interrupts`_ are used
  * and xe_memirq_init() didn't fail.
  *
  * Return: GGTT's offset of the `Interrupt Status Report Page`_.
  */
-u32 xe_memirq_status_ptr(struct xe_memirq *memirq)
+u32 xe_memirq_status_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe)
 {
+       u16 instance;
+
        memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq)));
        memirq_assert(memirq, memirq->bo);
 
-       return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_STATUS_OFFSET;
+       instance = hw_reports_to_instance_zero(memirq) ? hwe->instance : 0;
+
+       return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_STATUS_OFFSET(instance);
 }
 
 /**
@@ -284,8 +345,8 @@ int xe_memirq_init_guc(struct xe_memirq *memirq, struct xe_guc *guc)
        memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq)));
        memirq_assert(memirq, memirq->bo);
 
-       source = xe_memirq_source_ptr(memirq) + offset;
-       status = xe_memirq_status_ptr(memirq) + offset * SZ_16;
+       source = xe_memirq_source_ptr(memirq, NULL) + offset;
+       status = xe_memirq_status_ptr(memirq, NULL) + offset * SZ_16;
 
        err = xe_guc_self_cfg64(guc, GUC_KLV_SELF_CFG_MEMIRQ_SOURCE_ADDR_KEY,
                                source);
index 2d40d03c309561a0e26268587105a8a545f5b3f1..15efae2a7a55813b63537a48bcb27e722a7d2f0f 100644 (file)
@@ -9,12 +9,13 @@
 #include <linux/types.h>
 
 struct xe_guc;
+struct xe_hw_engine;
 struct xe_memirq;
 
 int xe_memirq_init(struct xe_memirq *memirq);
 
-u32 xe_memirq_source_ptr(struct xe_memirq *memirq);
-u32 xe_memirq_status_ptr(struct xe_memirq *memirq);
+u32 xe_memirq_source_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe);
+u32 xe_memirq_status_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe);
 u32 xe_memirq_enable_ptr(struct xe_memirq *memirq);
 
 void xe_memirq_reset(struct xe_memirq *memirq);
index 625b6b8736cc42a161df44fc10496ff12e063814..9d0f6c1cdb9d5caca5d0c4ef828372e82cea0fe2 100644 (file)
@@ -11,9 +11,9 @@
 struct xe_bo;
 
 /* ISR */
-#define XE_MEMIRQ_STATUS_OFFSET                0x0
+#define XE_MEMIRQ_STATUS_OFFSET(inst)  ((inst) * SZ_4K + 0x0)
 /* IIR */
-#define XE_MEMIRQ_SOURCE_OFFSET                0x400
+#define XE_MEMIRQ_SOURCE_OFFSET(inst)  ((inst) * SZ_4K + 0x400)
 /* IMR */
 #define XE_MEMIRQ_ENABLE_OFFSET                0x440