1 // SPDX-License-Identifier: MIT 2 /* 3 * Copyright © 2023 Intel Corporation 4 */ 5 6 #include <drm/drm_managed.h> 7 8 #include "regs/xe_guc_regs.h" 9 #include "regs/xe_irq_regs.h" 10 11 #include "xe_assert.h" 12 #include "xe_bo.h" 13 #include "xe_device.h" 14 #include "xe_device_types.h" 15 #include "xe_gt.h" 16 #include "xe_guc.h" 17 #include "xe_hw_engine.h" 18 #include "xe_memirq.h" 19 #include "xe_tile_printk.h" 20 21 #define memirq_assert(m, condition) xe_tile_assert(memirq_to_tile(m), condition) 22 #define memirq_printk(m, _level, _fmt, ...) \ 23 xe_tile_##_level(memirq_to_tile(m), "MEMIRQ: " _fmt, ##__VA_ARGS__) 24 25 #ifdef CONFIG_DRM_XE_DEBUG_MEMIRQ 26 #define memirq_debug(m, _fmt, ...) memirq_printk(m, dbg, _fmt, ##__VA_ARGS__) 27 #else 28 #define memirq_debug(...) 29 #endif 30 31 #define memirq_err(m, _fmt, ...) memirq_printk(m, err, _fmt, ##__VA_ARGS__) 32 #define memirq_err_ratelimited(m, _fmt, ...) \ 33 memirq_printk(m, err_ratelimited, _fmt, ##__VA_ARGS__) 34 35 static struct xe_tile *memirq_to_tile(struct xe_memirq *memirq) 36 { 37 return container_of(memirq, struct xe_tile, memirq); 38 } 39 40 static struct xe_device *memirq_to_xe(struct xe_memirq *memirq) 41 { 42 return tile_to_xe(memirq_to_tile(memirq)); 43 } 44 45 static const char *guc_name(struct xe_guc *guc) 46 { 47 return xe_gt_is_media_type(guc_to_gt(guc)) ? "media GuC" : "GuC"; 48 } 49 50 /** 51 * DOC: Memory Based Interrupts 52 * 53 * MMIO register based interrupts infrastructure used for non-virtualized mode 54 * or SRIOV-8 (which supports 8 Virtual Functions) does not scale efficiently 55 * to allow delivering interrupts to a large number of Virtual machines or 56 * containers. Memory based interrupt status reporting provides an efficient 57 * and scalable infrastructure. 58 * 59 * For memory based interrupt status reporting hardware sequence is: 60 * * Engine writes the interrupt event to memory 61 * (Pointer to memory location is provided by SW. This memory surface must 62 * be mapped to system memory and must be marked as un-cacheable (UC) on 63 * Graphics IP Caches) 64 * * Engine triggers an interrupt to host. 65 */ 66 67 /** 68 * DOC: Memory Based Interrupts Page Layout 69 * 70 * `Memory Based Interrupts`_ requires three different objects, which are 71 * called "page" in the specs, even if they aren't page-sized or aligned. 72 * 73 * To simplify the code we allocate a single page size object and then use 74 * offsets to embedded "pages". The address of those "pages" are then 75 * programmed in the HW via LRI and LRM in the context image. 76 * 77 * - _`Interrupt Status Report Page`: this page contains the interrupt 78 * status vectors for each unit. Each bit in the interrupt vectors is 79 * converted to a byte, with the byte being set to 0xFF when an 80 * interrupt is triggered; interrupt vectors are 16b big so each unit 81 * gets 16B. One space is reserved for each bit in one of the 82 * GT_INTR_DWx registers, so this object needs a total of 1024B. 83 * This object needs to be 4KiB aligned. 84 * 85 * - _`Interrupt Source Report Page`: this is the equivalent of the 86 * GT_INTR_DWx registers, with each bit in those registers being 87 * mapped to a byte here. The offsets are the same, just bytes instead 88 * of bits. This object needs to be cacheline aligned. 89 * 90 * - Interrupt Mask: the HW needs a location to fetch the interrupt 91 * mask vector to be used by the LRM in the context, so we just use 92 * the next available space in the interrupt page. 93 * 94 * :: 95 * 96 * 0x0000 +===========+ <== Interrupt Status Report Page 97 * | | 98 * | | ____ +----+----------------+ 99 * | | / | 0 | USER INTERRUPT | 100 * +-----------+ __/ | 1 | | 101 * | HWE(n) | __ | | CTX SWITCH | 102 * +-----------+ \ | | WAIT SEMAPHORE | 103 * | | \____ | 15 | | 104 * | | +----+----------------+ 105 * | | 106 * 0x0400 +===========+ <== Interrupt Source Report Page 107 * | HWE(0) | 108 * | HWE(1) | 109 * | | 110 * | HWE(x) | 111 * 0x0440 +===========+ <== Interrupt Enable Mask 112 * | | 113 * | | 114 * +-----------+ 115 * 116 * 117 * MSI-X use case 118 * 119 * When using MSI-X, hw engines report interrupt status and source to engine 120 * instance 0. For this scenario, in order to differentiate between the 121 * engines, we need to pass different status/source pointers in the LRC. 122 * 123 * The requirements on those pointers are: 124 * - Interrupt status should be 4KiB aligned 125 * - Interrupt source should be 64 bytes aligned 126 * 127 * To accommodate this, we duplicate the memirq page layout above - 128 * allocating a page for each engine instance and pass this page in the LRC. 129 * Note that the same page can be reused for different engine types. 130 * For example, an LRC executing on CCS #x will have pointers to page #x, 131 * and an LRC executing on BCS #x will have the same pointers. 132 * 133 * :: 134 * 135 * 0x0000 +==============================+ <== page for instance 0 (BCS0, CCS0, etc.) 136 * | Interrupt Status Report Page | 137 * 0x0400 +==============================+ 138 * | Interrupt Source Report Page | 139 * 0x0440 +==============================+ 140 * | Interrupt Enable Mask | 141 * +==============================+ 142 * | Not used | 143 * 0x1000 +==============================+ <== page for instance 1 (BCS1, CCS1, etc.) 144 * | Interrupt Status Report Page | 145 * 0x1400 +==============================+ 146 * | Interrupt Source Report Page | 147 * 0x1440 +==============================+ 148 * | Not used | 149 * 0x2000 +==============================+ <== page for instance 2 (BCS2, CCS2, etc.) 150 * | ... | 151 * +==============================+ 152 * 153 */ 154 155 /* ISR */ 156 #define XE_MEMIRQ_STATUS_OFFSET(inst) ((inst) * SZ_4K + 0x0) 157 /* IIR */ 158 #define XE_MEMIRQ_SOURCE_OFFSET(inst) ((inst) * SZ_4K + 0x400) 159 /* IMR */ 160 #define XE_MEMIRQ_ENABLE_OFFSET 0x440 161 162 /* engine ISR vector offset */ 163 #define XE_MEMIRQ_VECTOR_OFFSET(page, source) (XE_MEMIRQ_STATUS_OFFSET(page) + (source) * SZ_16) 164 165 static inline bool hw_reports_to_instance_zero(struct xe_memirq *memirq) 166 { 167 /* 168 * When the HW engines are configured to use MSI-X, 169 * they report interrupt status and source to the offset of 170 * engine instance 0. 171 */ 172 return xe_device_has_msix(memirq_to_xe(memirq)); 173 } 174 175 static unsigned int hwe_max_count(struct xe_tile *tile) 176 { 177 unsigned int max_instance = 0; 178 unsigned int gtid, hweid; 179 struct xe_hw_engine *hwe; 180 struct xe_gt *gt; 181 182 for_each_gt_on_tile(gt, tile, gtid) 183 for_each_hw_engine(hwe, gt, hweid) 184 max_instance = max(max_instance, hwe->instance); 185 186 return max_instance + 1; 187 } 188 189 static int memirq_alloc_pages(struct xe_memirq *memirq) 190 { 191 struct xe_device *xe = memirq_to_xe(memirq); 192 struct xe_tile *tile = memirq_to_tile(memirq); 193 unsigned int num_pages; 194 struct xe_bo *bo; 195 size_t bo_size; 196 int err; 197 198 BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_SOURCE_OFFSET(0), SZ_64)); 199 BUILD_BUG_ON(!IS_ALIGNED(XE_MEMIRQ_STATUS_OFFSET(0), SZ_4K)); 200 201 num_pages = hw_reports_to_instance_zero(memirq) ? hwe_max_count(tile) : 1; 202 bo_size = num_pages * SZ_4K; 203 204 bo = xe_managed_bo_create_pin_map(xe, tile, bo_size, 205 XE_BO_FLAG_SYSTEM | 206 XE_BO_FLAG_GGTT | 207 XE_BO_FLAG_GGTT_INVALIDATE | 208 XE_BO_FLAG_NEEDS_UC | 209 XE_BO_FLAG_NEEDS_CPU_ACCESS); 210 if (IS_ERR(bo)) { 211 err = PTR_ERR(bo); 212 goto out; 213 } 214 215 memirq_assert(memirq, !xe_bo_is_vram(bo)); 216 memirq_assert(memirq, !memirq->bo); 217 218 iosys_map_memset(&bo->vmap, 0, 0, bo_size); 219 220 memirq->bo = bo; 221 memirq->source = IOSYS_MAP_INIT_OFFSET(&bo->vmap, XE_MEMIRQ_SOURCE_OFFSET(0)); 222 memirq->num_pages = num_pages; 223 224 memirq_assert(memirq, !memirq->source.is_iomem); 225 226 memirq_debug(memirq, "pages: count %u size %zu\n", num_pages, bo_size); 227 memirq_debug(memirq, "page0: source %#x status %#x mask %#x\n", 228 xe_bo_ggtt_addr(bo) + XE_MEMIRQ_SOURCE_OFFSET(0), 229 xe_bo_ggtt_addr(bo) + XE_MEMIRQ_STATUS_OFFSET(0), 230 xe_bo_ggtt_addr(bo) + XE_MEMIRQ_ENABLE_OFFSET); 231 232 return 0; 233 234 out: 235 memirq_err(memirq, "Failed to allocate memirq page (%pe)\n", ERR_PTR(err)); 236 return err; 237 } 238 239 static void memirq_set_enable(struct xe_memirq *memirq, bool enable) 240 { 241 /* 242 * We only care about the GT_MI_USER_INTERRUPT from the engines and 243 * the GuC does not look at the ENABLE mask at all. 244 */ 245 iosys_map_wr(&memirq->bo->vmap, XE_MEMIRQ_ENABLE_OFFSET, u32, 246 enable ? GT_MI_USER_INTERRUPT : 0); 247 248 memirq->enabled = enable; 249 } 250 251 /** 252 * xe_memirq_init - Initialize data used by `Memory Based Interrupts`_. 253 * @memirq: the &xe_memirq to initialize 254 * 255 * Allocate `Interrupt Source Report Page`_ and `Interrupt Status Report Page`_ 256 * used by `Memory Based Interrupts`_. 257 * 258 * These allocations are managed and will be implicitly released on unload. 259 * 260 * If this function fails then the driver won't be able to operate correctly. 261 * If `Memory Based Interrupts`_ are not used this function will return 0. 262 * 263 * Return: 0 on success or a negative error code on failure. 264 */ 265 int xe_memirq_init(struct xe_memirq *memirq) 266 { 267 struct xe_device *xe = memirq_to_xe(memirq); 268 int err; 269 270 if (!xe_device_uses_memirq(xe)) 271 return 0; 272 273 err = memirq_alloc_pages(memirq); 274 if (unlikely(err)) 275 return err; 276 277 /* we need to start with all irqs enabled */ 278 memirq_set_enable(memirq, true); 279 280 return 0; 281 } 282 283 /** 284 * xe_memirq_source_ptr - Get GGTT's offset of the `Interrupt Source Report Page`_. 285 * @memirq: the &xe_memirq to query 286 * @hwe: the hw engine for which we want the report page 287 * 288 * Shall be called when `Memory Based Interrupts`_ are used 289 * and xe_memirq_init() didn't fail. 290 * 291 * Return: GGTT's offset of the `Interrupt Source Report Page`_. 292 */ 293 u32 xe_memirq_source_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe) 294 { 295 memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); 296 297 return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_SOURCE_OFFSET(hwe->irq_page); 298 } 299 300 /** 301 * xe_memirq_status_ptr - Get GGTT's offset of the `Interrupt Status Report Page`_. 302 * @memirq: the &xe_memirq to query 303 * @hwe: the hw engine for which we want the report page 304 * 305 * Shall be called when `Memory Based Interrupts`_ are used 306 * and xe_memirq_init() didn't fail. 307 * 308 * Return: GGTT's offset of the `Interrupt Status Report Page`_. 309 */ 310 u32 xe_memirq_status_ptr(struct xe_memirq *memirq, struct xe_hw_engine *hwe) 311 { 312 memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); 313 314 return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_STATUS_OFFSET(hwe->irq_page); 315 } 316 317 /** 318 * xe_memirq_enable_ptr - Get GGTT's offset of the Interrupt Enable Mask. 319 * @memirq: the &xe_memirq to query 320 * 321 * Shall be called when `Memory Based Interrupts`_ are used 322 * and xe_memirq_init() didn't fail. 323 * 324 * Return: GGTT's offset of the Interrupt Enable Mask. 325 */ 326 u32 xe_memirq_enable_ptr(struct xe_memirq *memirq) 327 { 328 memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); 329 memirq_assert(memirq, memirq->bo); 330 331 return xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_ENABLE_OFFSET; 332 } 333 334 /** 335 * xe_memirq_init_guc - Prepare GuC for `Memory Based Interrupts`_. 336 * @memirq: the &xe_memirq 337 * @guc: the &xe_guc to setup 338 * 339 * Register `Interrupt Source Report Page`_ and `Interrupt Status Report Page`_ 340 * to be used by the GuC when `Memory Based Interrupts`_ are required. 341 * 342 * Shall be called when `Memory Based Interrupts`_ are used 343 * and xe_memirq_init() didn't fail. 344 * 345 * Return: 0 on success or a negative error code on failure. 346 */ 347 int xe_memirq_init_guc(struct xe_memirq *memirq, struct xe_guc *guc) 348 { 349 bool is_media = xe_gt_is_media_type(guc_to_gt(guc)); 350 u32 offset = is_media ? ilog2(INTR_MGUC) : ilog2(INTR_GUC); 351 u64 source, status; 352 int err; 353 354 memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); 355 356 /* GuC expects exact locations, it doesn't add anything on its own */ 357 source = xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_SOURCE_OFFSET(0) + offset; 358 status = xe_bo_ggtt_addr(memirq->bo) + XE_MEMIRQ_VECTOR_OFFSET(0, offset); 359 360 err = xe_guc_self_cfg64(guc, GUC_KLV_SELF_CFG_MEMIRQ_SOURCE_ADDR_KEY, 361 source); 362 if (unlikely(err)) 363 goto failed; 364 365 err = xe_guc_self_cfg64(guc, GUC_KLV_SELF_CFG_MEMIRQ_STATUS_ADDR_KEY, 366 status); 367 if (unlikely(err)) 368 goto failed; 369 370 return 0; 371 372 failed: 373 memirq_err(memirq, "Failed to setup report pages in %s (%pe)\n", 374 guc_name(guc), ERR_PTR(err)); 375 return err; 376 } 377 378 /** 379 * xe_memirq_reset - Disable processing of `Memory Based Interrupts`_. 380 * @memirq: struct xe_memirq 381 * 382 * This is part of the driver IRQ setup flow. 383 * 384 * This function shall only be used on platforms that use 385 * `Memory Based Interrupts`_. 386 */ 387 void xe_memirq_reset(struct xe_memirq *memirq) 388 { 389 memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); 390 391 if (memirq->bo) 392 memirq_set_enable(memirq, false); 393 } 394 395 /** 396 * xe_memirq_postinstall - Enable processing of `Memory Based Interrupts`_. 397 * @memirq: the &xe_memirq 398 * 399 * This is part of the driver IRQ setup flow. 400 * 401 * This function shall only be used on platforms that use 402 * `Memory Based Interrupts`_. 403 */ 404 void xe_memirq_postinstall(struct xe_memirq *memirq) 405 { 406 memirq_assert(memirq, xe_device_uses_memirq(memirq_to_xe(memirq))); 407 408 if (memirq->bo) 409 memirq_set_enable(memirq, true); 410 } 411 412 static bool __memirq_received(struct xe_memirq *memirq, 413 struct iosys_map *vector, u16 offset, 414 const char *name, bool clear) 415 { 416 u8 value; 417 418 value = iosys_map_rd(vector, offset, u8); 419 if (value) { 420 if (value != 0xff) 421 memirq_err_ratelimited(memirq, 422 "Unexpected memirq value %#x from %s at %u\n", 423 value, name, offset); 424 if (clear) 425 iosys_map_wr(vector, offset, u8, 0x00); 426 } 427 428 return value; 429 } 430 431 static bool memirq_received_noclear(struct xe_memirq *memirq, 432 struct iosys_map *vector, 433 u16 offset, const char *name) 434 { 435 return __memirq_received(memirq, vector, offset, name, false); 436 } 437 438 static bool memirq_received(struct xe_memirq *memirq, struct iosys_map *vector, 439 u16 offset, const char *name) 440 { 441 return __memirq_received(memirq, vector, offset, name, true); 442 } 443 444 static void memirq_assume_received(struct xe_memirq *memirq, const char *source, 445 u16 offset, const char *status) 446 { 447 memirq_debug(memirq, "ASSUME %s %s(%u)\n", source, status, offset); 448 } 449 450 static void memirq_dispatch_engine(struct xe_memirq *memirq, struct iosys_map *status, 451 struct xe_hw_engine *hwe) 452 { 453 memirq_debug(memirq, "STATUS %s %*ph\n", hwe->name, 16, status->vaddr); 454 455 /* 456 * The programming note says to assume that GT_MI_USER_INTERRUPT is always 457 * set. Check and clear related status byte just for a debug. 458 */ 459 if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_MEMIRQ) && 460 !memirq_received(memirq, status, ilog2(GT_MI_USER_INTERRUPT), hwe->name)) 461 memirq_assume_received(memirq, hwe->name, ilog2(GT_MI_USER_INTERRUPT), "USER"); 462 xe_hw_engine_handle_irq(hwe, GT_MI_USER_INTERRUPT); 463 } 464 465 static void memirq_dispatch_guc(struct xe_memirq *memirq, struct iosys_map *status, 466 struct xe_guc *guc) 467 { 468 const char *name = guc_name(guc); 469 470 memirq_debug(memirq, "STATUS %s %*ph\n", name, 16, status->vaddr); 471 472 /* 473 * The programming note says to assume that GUC_INTR_GUC2HOST is always 474 * set. Check and clear related status byte just for a debug. 475 */ 476 if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_MEMIRQ) && 477 !memirq_received(memirq, status, ilog2(GUC_INTR_GUC2HOST), name)) 478 memirq_assume_received(memirq, name, ilog2(GUC_INTR_GUC2HOST), "GUC2HOST"); 479 xe_guc_irq_handler(guc, GUC_INTR_GUC2HOST); 480 481 /* 482 * This is a software interrupt that must be cleared after it's consumed 483 * to avoid race conditions where xe_gt_sriov_vf_recovery_pending() 484 * returns false. 485 */ 486 if (memirq_received_noclear(memirq, status, ilog2(GUC_INTR_SW_INT_0), 487 name)) { 488 xe_guc_irq_handler(guc, GUC_INTR_SW_INT_0); 489 iosys_map_wr(status, ilog2(GUC_INTR_SW_INT_0), u8, 0x00); 490 } 491 } 492 493 /** 494 * xe_memirq_hwe_handler - Check and process interrupts for a specific HW engine. 495 * @memirq: the &xe_memirq 496 * @hwe: the hw engine to process 497 * 498 * This function reads and dispatches `Memory Based Interrupts` for the provided HW engine. 499 */ 500 void xe_memirq_hwe_handler(struct xe_memirq *memirq, struct xe_hw_engine *hwe) 501 { 502 struct iosys_map source = 503 IOSYS_MAP_INIT_OFFSET(&memirq->bo->vmap, 504 XE_MEMIRQ_SOURCE_OFFSET(hwe->irq_page)); 505 506 if (memirq_received(memirq, &source, hwe->irq_offset, "SRC")) { 507 struct iosys_map status = 508 IOSYS_MAP_INIT_OFFSET(&memirq->bo->vmap, 509 XE_MEMIRQ_VECTOR_OFFSET(hwe->irq_page, 510 hwe->irq_offset)); 511 memirq_dispatch_engine(memirq, &status, hwe); 512 } 513 } 514 515 /** 516 * xe_memirq_guc_sw_int_0_irq_pending() - SW_INT_0 IRQ is pending 517 * @memirq: the &xe_memirq 518 * @guc: the &xe_guc to check for IRQ 519 * 520 * Return: True if SW_INT_0 IRQ is pending on @guc, False otherwise 521 */ 522 bool xe_memirq_guc_sw_int_0_irq_pending(struct xe_memirq *memirq, struct xe_guc *guc) 523 { 524 struct xe_gt *gt = guc_to_gt(guc); 525 u32 offset = xe_gt_is_media_type(gt) ? ilog2(INTR_MGUC) : ilog2(INTR_GUC); 526 struct iosys_map map = IOSYS_MAP_INIT_OFFSET(&memirq->bo->vmap, 527 XE_MEMIRQ_VECTOR_OFFSET(0, offset)); 528 529 return memirq_received_noclear(memirq, &map, ilog2(GUC_INTR_SW_INT_0), 530 guc_name(guc)); 531 } 532 533 static void memirq_dump_source_pages(struct xe_memirq *memirq) 534 { 535 memirq_assert(memirq, !memirq->bo->vmap.is_iomem); 536 537 for (int n = 0; n < memirq->num_pages; n++) { 538 memirq_debug(memirq, "SOURCE %*ph\n", 32, 539 memirq->bo->vmap.vaddr + XE_MEMIRQ_SOURCE_OFFSET(n)); 540 memirq_debug(memirq, "SOURCE %*ph\n", 32, 541 memirq->bo->vmap.vaddr + XE_MEMIRQ_SOURCE_OFFSET(n) + 32); 542 } 543 } 544 545 /** 546 * xe_memirq_handler - The `Memory Based Interrupts`_ Handler. 547 * @memirq: the &xe_memirq 548 * 549 * This function reads and dispatches `Memory Based Interrupts`. 550 */ 551 void xe_memirq_handler(struct xe_memirq *memirq) 552 { 553 struct xe_device *xe = memirq_to_xe(memirq); 554 struct xe_tile *tile = memirq_to_tile(memirq); 555 struct xe_hw_engine *hwe; 556 enum xe_hw_engine_id id; 557 struct iosys_map map; 558 unsigned int gtid; 559 struct xe_gt *gt; 560 561 if (!memirq->bo) 562 return; 563 564 if (IS_ENABLED(CONFIG_DRM_XE_DEBUG_MEMIRQ)) 565 memirq_dump_source_pages(memirq); 566 567 for_each_gt(gt, xe, gtid) { 568 if (gt->tile != tile) 569 continue; 570 571 for_each_hw_engine(hwe, gt, id) 572 xe_memirq_hwe_handler(memirq, hwe); 573 } 574 575 /* GuC and media GuC (if present) must be checked separately */ 576 577 if (memirq_received(memirq, &memirq->source, ilog2(INTR_GUC), "SRC")) { 578 map = IOSYS_MAP_INIT_OFFSET(&memirq->bo->vmap, 579 XE_MEMIRQ_VECTOR_OFFSET(0, ilog2(INTR_GUC))); 580 memirq_dispatch_guc(memirq, &map, &tile->primary_gt->uc.guc); 581 } 582 583 if (!tile->media_gt) 584 return; 585 586 if (memirq_received(memirq, &memirq->source, ilog2(INTR_MGUC), "SRC")) { 587 map = IOSYS_MAP_INIT_OFFSET(&memirq->bo->vmap, 588 XE_MEMIRQ_VECTOR_OFFSET(0, ilog2(INTR_MGUC))); 589 memirq_dispatch_guc(memirq, &map, &tile->media_gt->uc.guc); 590 } 591 } 592