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

drm/xe: memirq infra changes for MSI-X

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

authored by

Ilia Levi and committed by
Michal Wajdeczko
ef6103d2 4157849c

+89 -21
+7 -1
drivers/gpu/drm/xe/xe_device.h
··· 155 155 return xe->info.has_sriov; 156 156 } 157 157 158 + static inline bool xe_device_has_msix(struct xe_device *xe) 159 + { 160 + /* TODO: change this when MSI-X support is fully integrated */ 161 + return false; 162 + } 163 + 158 164 static inline bool xe_device_has_memirq(struct xe_device *xe) 159 165 { 160 166 return GRAPHICS_VERx100(xe) >= 1250; ··· 168 162 169 163 static inline bool xe_device_uses_memirq(struct xe_device *xe) 170 164 { 171 - return xe_device_has_memirq(xe) && IS_SRIOV_VF(xe); 165 + return xe_device_has_memirq(xe) && (IS_SRIOV_VF(xe) || xe_device_has_msix(xe)); 172 166 } 173 167 174 168 u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size);
+2 -2
drivers/gpu/drm/xe/xe_lrc.c
··· 613 613 regs[CTX_LRI_INT_REPORT_PTR] = MI_LOAD_REGISTER_IMM | MI_LRI_NUM_REGS(2) | 614 614 MI_LRI_LRM_CS_MMIO | MI_LRI_FORCE_POSTED; 615 615 regs[CTX_INT_STATUS_REPORT_REG] = RING_INT_STATUS_RPT_PTR(0).addr; 616 - regs[CTX_INT_STATUS_REPORT_PTR] = xe_memirq_status_ptr(memirq); 616 + regs[CTX_INT_STATUS_REPORT_PTR] = xe_memirq_status_ptr(memirq, hwe); 617 617 regs[CTX_INT_SRC_REPORT_REG] = RING_INT_SRC_RPT_PTR(0).addr; 618 - regs[CTX_INT_SRC_REPORT_PTR] = xe_memirq_source_ptr(memirq); 618 + regs[CTX_INT_SRC_REPORT_PTR] = xe_memirq_source_ptr(memirq, hwe); 619 619 } 620 620 621 621 static int lrc_ring_mi_mode(struct xe_hw_engine *hwe)
+75 -14
drivers/gpu/drm/xe/xe_memirq.c
··· 115 115 * | | 116 116 * | | 117 117 * +-----------+ 118 + * 119 + * 120 + * MSI-X use case 121 + * 122 + * When using MSI-X, hw engines report interrupt status and source to engine 123 + * instance 0. For this scenario, in order to differentiate between the 124 + * engines, we need to pass different status/source pointers in the LRC. 125 + * 126 + * The requirements on those pointers are: 127 + * - Interrupt status should be 4KiB aligned 128 + * - Interrupt source should be 64 bytes aligned 129 + * 130 + * To accommodate this, we duplicate the memirq page layout above - 131 + * allocating a page for each engine instance and pass this page in the LRC. 132 + * Note that the same page can be reused for different engine types. 133 + * For example, an LRC executing on CCS #x will have pointers to page #x, 134 + * and an LRC executing on BCS #x will have the same pointers. 135 + * 136 + * :: 137 + * 138 + * 0x0000 +==============================+ <== page for instance 0 (BCS0, CCS0, etc.) 139 + * | Interrupt Status Report Page | 140 + * 0x0400 +==============================+ 141 + * | Interrupt Source Report Page | 142 + * 0x0440 +==============================+ 143 + * | Interrupt Enable Mask | 144 + * +==============================+ 145 + * | Not used | 146 + * 0x1000 +==============================+ <== page for instance 1 (BCS1, CCS1, etc.) 147 + * | Interrupt Status Report Page | 148 + * 0x1400 +==============================+ 149 + * | Interrupt Source Report Page | 150 + * 0x1440 +==============================+ 151 + * | Not used | 152 + * 0x2000 +==============================+ <== page for instance 2 (BCS2, CCS2, etc.) 153 + * | ... | 154 + * +==============================+ 155 + * 118 156 */ 119 157 120 158 static void __release_xe_bo(struct drm_device *drm, void *arg) ··· 162 124 xe_bo_unpin_map_no_vm(bo); 163 125 } 164 126 127 + static inline bool hw_reports_to_instance_zero(struct xe_memirq *memirq) 128 + { 129 + /* 130 + * When the HW engines are configured to use MSI-X, 131 + * they report interrupt status and source to the offset of 132 + * engine instance 0. 133 + */ 134 + return xe_device_has_msix(memirq_to_xe(memirq)); 135 + } 136 + 165 137 static int memirq_alloc_pages(struct xe_memirq *memirq) 166 138 { 167 139 struct xe_device *xe = memirq_to_xe(memirq); 168 140 struct xe_tile *tile = memirq_to_tile(memirq); 141 + size_t bo_size = hw_reports_to_instance_zero(memirq) ? 142 + XE_HW_ENGINE_MAX_INSTANCE * SZ_4K : SZ_4K; 169 143 struct xe_bo *bo; 170 144 int err; 171 145 172 - BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_SOURCE_OFFSET, SZ_64)); 173 - BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_STATUS_OFFSET, SZ_4K)); 146 + BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_SOURCE_OFFSET(0), SZ_64)); 147 + BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_STATUS_OFFSET(0), SZ_4K)); 174 148 175 149 /* XXX: convert to managed bo */ 176 - bo = xe_bo_create_pin_map(xe, tile, NULL, SZ_4K, 150 + bo = xe_bo_create_pin_map(xe, tile, NULL, bo_size, 177 151 ttm_bo_type_kernel, 178 152 XE_BO_FLAG_SYSTEM | 179 153 XE_BO_FLAG_GGTT | ··· 200 150 memirq_assert(memirq, !xe_bo_is_vram(bo)); 201 151 memirq_assert(memirq, !memirq->bo); 202 152 203 - iosys_map_memset(&bo->vmap, 0, 0, SZ_4K); 153 + iosys_map_memset(&bo->vmap, 0, 0, bo_size); 204 154 205 155 memirq->bo = bo; 206 - memirq->source = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_SOURCE_OFFSET); 207 - memirq->status = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_STATUS_OFFSET); 156 + memirq->source = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_SOURCE_OFFSET(0)); 157 + memirq->status = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_STATUS_OFFSET(0)); 208 158 memirq->mask = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_ENABLE_OFFSET); 209 159 210 160 memirq_assert(memirq, !memirq->source.is_iomem); 211 161 memirq_assert(memirq, !memirq->status.is_iomem); 212 162 memirq_assert(memirq, !memirq->mask.is_iomem); 213 163 214 - memirq_debug(memirq, "page offsets: source %#x status %#x\n", 215 - xe_memirq_source_ptr(memirq), xe_memirq_status_ptr(memirq)); 164 + memirq_debug(memirq, "page offsets: bo %#x bo_size %zu source %#x status %#x\n", 165 + xe_bo_ggtt_addr(bo), bo_size, XE_MEMIRQ_SOURCE_OFFSET(0), 166 + XE_MEMIRQ_STATUS_OFFSET(0)); 216 167 217 168 return drmm_add_action_or_reset(&xe->drm, __release_xe_bo, memirq->bo); 218 169 ··· 264 213 /** 265 214 * xe_memirq_source_ptr - Get GGTT's offset of the `Interrupt Source Report Page`_. 266 215 * @memirq: the &xe_memirq to query 216 + * @hwe: the hw engine for which we want the report page 267 217 * 268 218 * Shall be called when `Memory Based Interrupts`_ are used 269 219 * and xe_memirq_init() didn't fail. 270 220 * 271 221 * Return: GGTT's offset of the `Interrupt Source Report Page`_. 272 222 */ 273 - u32 xe_memirq_source_ptr(struct xe_memirq *memirq) 223 + u32 xe_memirq_source_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe) 274 224 { 225 + u16 instance; 226 + 275 227 memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); 276 228 memirq_assert(memirq, memirq->bo); 277 229 278 - return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_SOURCE_OFFSET; 230 + instance = hw_reports_to_instance_zero(memirq) ? hwe->instance : 0; 231 + 232 + return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_SOURCE_OFFSET(instance); 279 233 } 280 234 281 235 /** 282 236 * xe_memirq_status_ptr - Get GGTT's offset of the `Interrupt Status Report Page`_. 283 237 * @memirq: the &xe_memirq to query 238 + * @hwe: the hw engine for which we want the report page 284 239 * 285 240 * Shall be called when `Memory Based Interrupts`_ are used 286 241 * and xe_memirq_init() didn't fail. 287 242 * 288 243 * Return: GGTT's offset of the `Interrupt Status Report Page`_. 289 244 */ 290 - u32 xe_memirq_status_ptr(struct xe_memirq *memirq) 245 + u32 xe_memirq_status_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe) 291 246 { 247 + u16 instance; 248 + 292 249 memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); 293 250 memirq_assert(memirq, memirq->bo); 294 251 295 - return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_STATUS_OFFSET; 252 + instance = hw_reports_to_instance_zero(memirq) ? hwe->instance : 0; 253 + 254 + return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_STATUS_OFFSET(instance); 296 255 } 297 256 298 257 /** ··· 345 284 memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); 346 285 memirq_assert(memirq, memirq->bo); 347 286 348 - source = xe_memirq_source_ptr(memirq) + offset; 349 - status = xe_memirq_status_ptr(memirq) + offset * SZ_16; 287 + source = xe_memirq_source_ptr(memirq, NULL) + offset; 288 + status = xe_memirq_status_ptr(memirq, NULL) + offset * SZ_16; 350 289 351 290 err = xe_guc_self_cfg64(guc, GUC_KLV_SELF_CFG_MEMIRQ_SOURCE_ADDR_KEY, 352 291 source);
+3 -2
drivers/gpu/drm/xe/xe_memirq.h
··· 9 9 #include <linux/types.h> 10 10 11 11 struct xe_guc; 12 + struct xe_hw_engine; 12 13 struct xe_memirq; 13 14 14 15 int xe_memirq_init(struct xe_memirq *memirq); 15 16 16 - u32 xe_memirq_source_ptr(struct xe_memirq *memirq); 17 - u32 xe_memirq_status_ptr(struct xe_memirq *memirq); 17 + u32 xe_memirq_source_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe); 18 + u32 xe_memirq_status_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe); 18 19 u32 xe_memirq_enable_ptr(struct xe_memirq *memirq); 19 20 20 21 void xe_memirq_reset(struct xe_memirq *memirq);
+2 -2
drivers/gpu/drm/xe/xe_memirq_types.h
··· 11 11 struct xe_bo; 12 12 13 13 /* ISR */ 14 - #define XE_MEMIRQ_STATUS_OFFSET 0x0 14 + #define XE_MEMIRQ_STATUS_OFFSET(inst) ((inst) * SZ_4K + 0x0) 15 15 /* IIR */ 16 - #define XE_MEMIRQ_SOURCE_OFFSET 0x400 16 + #define XE_MEMIRQ_SOURCE_OFFSET(inst) ((inst) * SZ_4K + 0x400) 17 17 /* IMR */ 18 18 #define XE_MEMIRQ_ENABLE_OFFSET 0x440 19 19