[airlied: fix guc submit double definition] UAPI Changes: - Multi-Queue support (Niranjana) - Add DRM_XE_EXEC_QUEUE_SET_HANG_REPLAY_STATE (Brost) - Add NO_COMPRESSION BO flag and query capability (Sanjay) - Add gt_id to struct drm_xe_oa_unit (Ashutosh) - Expose MERT OA unit (Ashutosh) - Sysfs Survivability refactor (Riana) Cross-subsystem Changes: - VFIO: Add device specific vfio_pci driver variant for Intel graphics (Winiarski) Driver Changes: - MAINTAINERS update (Lucas -> Matt) - Add helper to query compression enable status (Xin) - Xe_VM fixes and updates (Shuicheng, Himal) - Documentation fixes (Winiarski, Swaraj, Niranjana) - Kunit fix (Roper) - Fix potential leaks, uaf, null derref, and oversized allocations (Shuicheng, Sanjay, Mika, Tapani) - Other minor fixes like kbuild duplication and sysfs_emit (Shuicheng, Madhur) - Handle msix vector0 interrupt (Venkata) - Scope-based forcewake and runtime PM (Roper, Raag) - GuC/HuC related fixes and refactors (Lucas, Zhanjun, Brost, Julia, Wajdeczko) - Fix conversion from clock ticks to milliseconds (Harish) - SRIOV PF PF: Add support for MERT (Lukasz) - Enable SR-IOV VF migration and other SRIOV updates (Winiarski, Satya, Brost, Wajdeczko, Piotr, Tomasz, Daniele) - Optimize runtime suspend/resume and other PM improvements (Raag) - Some W/a additions and updates (Bala, Harish, Roper) - Use for_each_tlb_inval() to calculate invalidation fences (Roper) - Fix VFIO link error (Arnd) - Fix ix drm_gpusvm_init() arguments (Arnd) - Other OA refactor (Ashutosh) - Refactor PAT and expose debugfs (Xin) - Enable Indirect Ring State for xe3p_xpc (Niranjana) - MEI interrupt fix (Junxiao) - Add stats for mode switching on hw_engine_group (Francois) - DMA-Buf related changes (Thomas) - Multi Queue feature support (Niranjana) - Enable I2C controller for Crescent Island (Raag) - Enable NVM for Crescent Island (Sasha) - Increase TDF timeout (Jagmeet) - Restore engine registers before restarting schedulers after GT reset (Jan) - Page Reclamation Support for Xe3p Platforms (Brian, Brost, Oak) - Fix performance when pagefaults and 3d/display share resources (Brost) - More OA MERT work (Ashutosh) - Fix return values (Dan) - Some log level and messages improvements (Brost) Signed-off-by: Dave Airlie <airlied@redhat.com>
Unified · Split
| @@ -481,6 +481,7 @@ Lorenzo Pieralisi <lpieralisi@kernel.org> <lorenzo.pieralisi@arm.com> · 480 unmodified lines | |||
| 481 | Lorenzo Stoakes <lorenzo.stoakes@oracle.com> <lstoakes@gmail.com> | 481 | Lorenzo Stoakes <lorenzo.stoakes@oracle.com> <lstoakes@gmail.com> |
| 482 | Luca Ceresoli <luca.ceresoli@bootlin.com> <luca@lucaceresoli.net> | 482 | Luca Ceresoli <luca.ceresoli@bootlin.com> <luca@lucaceresoli.net> |
| 483 | Luca Weiss <luca@lucaweiss.eu> <luca@z3ntu.xyz> | 483 | Luca Weiss <luca@lucaweiss.eu> <luca@z3ntu.xyz> |
| 484 | Lucas De Marchi <demarchi@kernel.org> <lucas.demarchi@intel.com> | ||
| 484 | Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com> | 485 | Lukasz Luba <lukasz.luba@arm.com> <l.luba@partner.samsung.com> |
| 485 | Luo Jie <quic_luoj@quicinc.com> <luoj@codeaurora.org> | 486 | Luo Jie <quic_luoj@quicinc.com> <luoj@codeaurora.org> |
| 486 | Lance Yang <lance.yang@linux.dev> <ioworker0@gmail.com> | 487 | Lance Yang <lance.yang@linux.dev> <ioworker0@gmail.com> |
| @@ -119,7 +119,7 @@ Description: · 118 unmodified lines | |||
| 119 | The GT preemption timeout (PT) in [us] to be applied to all functions. | 119 | The GT preemption timeout (PT) in [us] to be applied to all functions. |
| 120 | See sriov_admin/{pf,vf<N>}/profile/preempt_timeout_us for more details. | 120 | See sriov_admin/{pf,vf<N>}/profile/preempt_timeout_us for more details. |
| 121 | 121 | ||
| 122 | sched_priority: (RW/RO) string | 122 | sched_priority: (WO) string |
| 123 | The GT scheduling priority to be applied for all functions. | 123 | The GT scheduling priority to be applied for all functions. |
| 124 | See sriov_admin/{pf,vf<N>}/profile/sched_priority for more details. | 124 | See sriov_admin/{pf,vf<N>}/profile/sched_priority for more details. |
| 125 | 125 | ||
| @@ -7,6 +7,20 @@ Execution Queue · 6 unmodified lines | |||
| 7 | .. kernel-doc:: drivers/gpu/drm/xe/xe_exec_queue.c | 7 | .. kernel-doc:: drivers/gpu/drm/xe/xe_exec_queue.c |
| 8 | :doc: Execution Queue | 8 | :doc: Execution Queue |
| 9 | 9 | ||
| 10 | Multi Queue Group | ||
| 11 | ================= | ||
| 12 | |||
| 13 | .. kernel-doc:: drivers/gpu/drm/xe/xe_exec_queue.c | ||
| 14 | :doc: Multi Queue Group | ||
| 15 | |||
| 16 | .. _multi-queue-group-guc-interface: | ||
| 17 | |||
| 18 | Multi Queue Group GuC interface | ||
| 19 | =============================== | ||
| 20 | |||
| 21 | .. kernel-doc:: drivers/gpu/drm/xe/xe_guc_submit.c | ||
| 22 | :doc: Multi Queue Group GuC interface | ||
| 23 | |||
| 10 | Internal API | 24 | Internal API |
| 11 | ============ | 25 | ============ |
| 12 | 26 | ||
| @@ -12640,7 +12640,7 @@ F: include/drm/intel/ · 12639 unmodified lines | |||
| 12640 | F: include/uapi/drm/i915_drm.h | 12640 | F: include/uapi/drm/i915_drm.h |
| 12641 | 12641 | ||
| 12642 | INTEL DRM XE DRIVER (Lunar Lake and newer) | 12642 | INTEL DRM XE DRIVER (Lunar Lake and newer) |
| 12643 | M: Lucas De Marchi <lucas.demarchi@intel.com> | 12643 | M: Matthew Brost <matthew.brost@intel.com> |
| 12644 | M: Thomas Hellström <thomas.hellstrom@linux.intel.com> | 12644 | M: Thomas Hellström <thomas.hellstrom@linux.intel.com> |
| 12645 | M: Rodrigo Vivi <rodrigo.vivi@intel.com> | 12645 | M: Rodrigo Vivi <rodrigo.vivi@intel.com> |
| 12646 | L: intel-xe@lists.freedesktop.org | 12646 | L: intel-xe@lists.freedesktop.org |
| @@ -1288,6 +1288,9 @@ int drm_gpusvm_get_pages(struct drm_gpusvm *gpusvm, · 1287 unmodified lines | |||
| 1288 | DMA_BIDIRECTIONAL; | 1288 | DMA_BIDIRECTIONAL; |
| 1289 | 1289 | ||
| 1290 | retry: | 1290 | retry: |
| 1291 | if (time_after(jiffies, timeout)) | ||
| 1292 | return -EBUSY; | ||
| 1293 | |||
| 1291 | hmm_range.notifier_seq = mmu_interval_read_begin(notifier); | 1294 | hmm_range.notifier_seq = mmu_interval_read_begin(notifier); |
| 1292 | if (drm_gpusvm_pages_valid_unlocked(gpusvm, svm_pages)) | 1295 | if (drm_gpusvm_pages_valid_unlocked(gpusvm, svm_pages)) |
| 1293 | goto set_seqno; | 1296 | goto set_seqno; |
| @@ -95,6 +95,7 @@ xe-y += xe_bb.o \ · 94 unmodified lines | |||
| 95 | xe_oa.o \ | 95 | xe_oa.o \ |
| 96 | xe_observation.o \ | 96 | xe_observation.o \ |
| 97 | xe_pagefault.o \ | 97 | xe_pagefault.o \ |
| 98 | xe_page_reclaim.o \ | ||
| 98 | xe_pat.o \ | 99 | xe_pat.o \ |
| 99 | xe_pci.o \ | 100 | xe_pci.o \ |
| 100 | xe_pcode.o \ | 101 | xe_pcode.o \ |
| @@ -173,6 +174,7 @@ xe-$(CONFIG_PCI_IOV) += \ · 72 unmodified lines | |||
| 173 | xe_lmtt.o \ | 174 | xe_lmtt.o \ |
| 174 | xe_lmtt_2l.o \ | 175 | xe_lmtt_2l.o \ |
| 175 | xe_lmtt_ml.o \ | 176 | xe_lmtt_ml.o \ |
| 177 | xe_mert.o \ | ||
| 176 | xe_pci_sriov.o \ | 178 | xe_pci_sriov.o \ |
| 177 | xe_sriov_packet.o \ | 179 | xe_sriov_packet.o \ |
| 178 | xe_sriov_pf.o \ | 180 | xe_sriov_pf.o \ |
| @@ -139,6 +139,10 @@ enum xe_guc_action { · 138 unmodified lines | |||
| 139 | XE_GUC_ACTION_DEREGISTER_G2G = 0x4508, | 139 | XE_GUC_ACTION_DEREGISTER_G2G = 0x4508, |
| 140 | XE_GUC_ACTION_DEREGISTER_CONTEXT_DONE = 0x4600, | 140 | XE_GUC_ACTION_DEREGISTER_CONTEXT_DONE = 0x4600, |
| 141 | XE_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC = 0x4601, | 141 | XE_GUC_ACTION_REGISTER_CONTEXT_MULTI_LRC = 0x4601, |
| 142 | XE_GUC_ACTION_REGISTER_CONTEXT_MULTI_QUEUE = 0x4602, | ||
| 143 | XE_GUC_ACTION_MULTI_QUEUE_CONTEXT_CGP_SYNC = 0x4603, | ||
| 144 | XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CONTEXT_CGP_SYNC_DONE = 0x4604, | ||
| 145 | XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CGP_CONTEXT_ERROR = 0x4605, | ||
| 142 | XE_GUC_ACTION_CLIENT_SOFT_RESET = 0x5507, | 146 | XE_GUC_ACTION_CLIENT_SOFT_RESET = 0x5507, |
| 143 | XE_GUC_ACTION_SET_ENG_UTIL_BUFF = 0x550A, | 147 | XE_GUC_ACTION_SET_ENG_UTIL_BUFF = 0x550A, |
| 144 | XE_GUC_ACTION_SET_DEVICE_ENGINE_ACTIVITY_BUFFER = 0x550C, | 148 | XE_GUC_ACTION_SET_DEVICE_ENGINE_ACTIVITY_BUFFER = 0x550C, |
| @@ -151,6 +155,8 @@ enum xe_guc_action { · 6 unmodified lines | |||
| 151 | XE_GUC_ACTION_TLB_INVALIDATION = 0x7000, | 155 | XE_GUC_ACTION_TLB_INVALIDATION = 0x7000, |
| 152 | XE_GUC_ACTION_TLB_INVALIDATION_DONE = 0x7001, | 156 | XE_GUC_ACTION_TLB_INVALIDATION_DONE = 0x7001, |
| 153 | XE_GUC_ACTION_TLB_INVALIDATION_ALL = 0x7002, | 157 | XE_GUC_ACTION_TLB_INVALIDATION_ALL = 0x7002, |
| 158 | XE_GUC_ACTION_PAGE_RECLAMATION = 0x7003, | ||
| 159 | XE_GUC_ACTION_PAGE_RECLAMATION_DONE = 0x7004, | ||
| 154 | XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION = 0x8002, | 160 | XE_GUC_ACTION_STATE_CAPTURE_NOTIFICATION = 0x8002, |
| 155 | XE_GUC_ACTION_NOTIFY_FLUSH_LOG_BUFFER_TO_FILE = 0x8003, | 161 | XE_GUC_ACTION_NOTIFY_FLUSH_LOG_BUFFER_TO_FILE = 0x8003, |
| 156 | XE_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED = 0x8004, | 162 | XE_GUC_ACTION_NOTIFY_CRASH_DUMP_POSTED = 0x8004, |
| @@ -502,13 +502,17 @@ · 501 unmodified lines | |||
| 502 | #define VF2GUC_VF_RESET_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0 | 502 | #define VF2GUC_VF_RESET_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0 |
| 503 | 503 | ||
| 504 | /** | 504 | /** |
| 505 | * DOC: VF2GUC_NOTIFY_RESFIX_DONE | 505 | * DOC: VF2GUC_RESFIX_DONE |
| 506 | * | 506 | * |
| 507 | * This action is used by VF to notify the GuC that the VF KMD has completed | 507 | * This action is used by VF to inform the GuC that the VF KMD has completed |
| 508 | * post-migration recovery steps. | 508 | * post-migration recovery steps. From GuC VF compatibility 1.27.0 onwards, it |
| 509 | * shall only be sent after posting RESFIX_START and that both @MARKER fields | ||
| 510 | * must match. | ||
| 509 | * | 511 | * |
| 510 | * This message must be sent as `MMIO HXG Message`_. | 512 | * This message must be sent as `MMIO HXG Message`_. |
| 511 | * | 513 | * |
| 514 | * Updated since GuC VF compatibility 1.27.0. | ||
| 515 | * | ||
| 512 | * +---+-------+--------------------------------------------------------------+ | 516 | * +---+-------+--------------------------------------------------------------+ |
| 513 | * | | Bits | Description | | 517 | * | | Bits | Description | |
| 514 | * +===+=======+==============================================================+ | 518 | * +===+=======+==============================================================+ |
| @@ -516,9 +520,11 @@ · 1 unmodified line | |||
| 516 | * | +-------+--------------------------------------------------------------+ | 520 | * | +-------+--------------------------------------------------------------+ |
| 517 | * | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ | | 521 | * | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ | |
| 518 | * | +-------+--------------------------------------------------------------+ | 522 | * | +-------+--------------------------------------------------------------+ |
| 519 | * | | 27:16 | DATA0 = MBZ | | 523 | * | | 27:16 | DATA0 = MARKER = MBZ (only prior 1.27.0) | |
| 520 | * | +-------+--------------------------------------------------------------+ | 524 | * | +-------+--------------------------------------------------------------+ |
| 521 | * | | 15:0 | ACTION = _`GUC_ACTION_VF2GUC_NOTIFY_RESFIX_DONE` = 0x5508 | | 525 | * | | 27:16 | DATA0 = MARKER - can't be zero (1.27.0+) | |
| 526 | * | +-------+--------------------------------------------------------------+ | ||
| 527 | * | | 15:0 | ACTION = _`GUC_ACTION_VF2GUC_RESFIX_DONE` = 0x5508 | | ||
| 522 | * +---+-------+--------------------------------------------------------------+ | 528 | * +---+-------+--------------------------------------------------------------+ |
| 523 | * | 529 | * |
| 524 | * +---+-------+--------------------------------------------------------------+ | 530 | * +---+-------+--------------------------------------------------------------+ |
| @@ -531,13 +537,13 @@ · 6 unmodified lines | |||
| 531 | * | | 27:0 | DATA0 = MBZ | | 537 | * | | 27:0 | DATA0 = MBZ | |
| 532 | * +---+-------+--------------------------------------------------------------+ | 538 | * +---+-------+--------------------------------------------------------------+ |
| 533 | */ | 539 | */ |
| 534 | #define GUC_ACTION_VF2GUC_NOTIFY_RESFIX_DONE 0x5508u | 540 | #define GUC_ACTION_VF2GUC_RESFIX_DONE 0x5508u |
| 535 | 541 | ||
| 536 | #define VF2GUC_NOTIFY_RESFIX_DONE_REQUEST_MSG_LEN GUC_HXG_REQUEST_MSG_MIN_LEN | 542 | #define VF2GUC_RESFIX_DONE_REQUEST_MSG_LEN GUC_HXG_REQUEST_MSG_MIN_LEN |
| 537 | #define VF2GUC_NOTIFY_RESFIX_DONE_REQUEST_MSG_0_MBZ GUC_HXG_REQUEST_MSG_0_DATA0 | 543 | #define VF2GUC_RESFIX_DONE_REQUEST_MSG_0_MARKER GUC_HXG_REQUEST_MSG_0_DATA0 |
| 538 | 544 | ||
| 539 | #define VF2GUC_NOTIFY_RESFIX_DONE_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN | 545 | #define VF2GUC_RESFIX_DONE_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN |
| 540 | #define VF2GUC_NOTIFY_RESFIX_DONE_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0 | 546 | #define VF2GUC_RESFIX_DONE_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0 |
| 541 | 547 | ||
| 542 | /** | 548 | /** |
| 543 | * DOC: VF2GUC_QUERY_SINGLE_KLV | 549 | * DOC: VF2GUC_QUERY_SINGLE_KLV |
| @@ -656,4 +662,45 @@ · 112 unmodified lines | |||
| 656 | #define PF2GUC_SAVE_RESTORE_VF_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN | 662 | #define PF2GUC_SAVE_RESTORE_VF_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN |
| 657 | #define PF2GUC_SAVE_RESTORE_VF_RESPONSE_MSG_0_USED GUC_HXG_RESPONSE_MSG_0_DATA0 | 663 | #define PF2GUC_SAVE_RESTORE_VF_RESPONSE_MSG_0_USED GUC_HXG_RESPONSE_MSG_0_DATA0 |
| 658 | 664 | ||
| 665 | /** | ||
| 666 | * DOC: VF2GUC_RESFIX_START | ||
| 667 | * | ||
| 668 | * This action is used by VF to inform the GuC that the VF KMD will be starting | ||
| 669 | * post-migration recovery fixups. The @MARKER sent with this action must match | ||
| 670 | * with the MARKER posted in the VF2GUC_RESFIX_DONE message. | ||
| 671 | * | ||
| 672 | * This message must be sent as `MMIO HXG Message`_. | ||
| 673 | * | ||
| 674 | * Available since GuC VF compatibility 1.27.0. | ||
| 675 | * | ||
| 676 | * +---+-------+--------------------------------------------------------------+ | ||
| 677 | * | | Bits | Description | | ||
| 678 | * +===+=======+==============================================================+ | ||
| 679 | * | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_HOST_ | | ||
| 680 | * | +-------+--------------------------------------------------------------+ | ||
| 681 | * | | 30:28 | TYPE = GUC_HXG_TYPE_REQUEST_ | | ||
| 682 | * | +-------+--------------------------------------------------------------+ | ||
| 683 | * | | 27:16 | DATA0 = MARKER - can't be zero | | ||
| 684 | * | +-------+--------------------------------------------------------------+ | ||
| 685 | * | | 15:0 | ACTION = _`GUC_ACTION_VF2GUC_RESFIX_START` = 0x550F | | ||
| 686 | * +---+-------+--------------------------------------------------------------+ | ||
| 687 | * | ||
| 688 | * +---+-------+--------------------------------------------------------------+ | ||
| 689 | * | | Bits | Description | | ||
| 690 | * +===+=======+==============================================================+ | ||
| 691 | * | 0 | 31 | ORIGIN = GUC_HXG_ORIGIN_GUC_ | | ||
| 692 | * | +-------+--------------------------------------------------------------+ | ||
| 693 | * | | 30:28 | TYPE = GUC_HXG_TYPE_RESPONSE_SUCCESS_ | | ||
| 694 | * | +-------+--------------------------------------------------------------+ | ||
| 695 | * | | 27:0 | DATA0 = MBZ | | ||
| 696 | * +---+-------+--------------------------------------------------------------+ | ||
| 697 | */ | ||
| 698 | #define GUC_ACTION_VF2GUC_RESFIX_START 0x550Fu | ||
| 699 | |||
| 700 | #define VF2GUC_RESFIX_START_REQUEST_MSG_LEN GUC_HXG_REQUEST_MSG_MIN_LEN | ||
| 701 | #define VF2GUC_RESFIX_START_REQUEST_MSG_0_MARKER GUC_HXG_REQUEST_MSG_0_DATA0 | ||
| 702 | |||
| 703 | #define VF2GUC_RESFIX_START_RESPONSE_MSG_LEN GUC_HXG_RESPONSE_MSG_MIN_LEN | ||
| 704 | #define VF2GUC_RESFIX_START_RESPONSE_MSG_0_MBZ GUC_HXG_RESPONSE_MSG_0_DATA0 | ||
| 705 | |||
| 659 | #endif | 706 | #endif |
| @@ -352,6 +352,12 @@ enum { · 351 unmodified lines | |||
| 352 | * :1: NORMAL = schedule VF always, irrespective of whether it has work or not | 352 | * :1: NORMAL = schedule VF always, irrespective of whether it has work or not |
| 353 | * :2: HIGH = schedule VF in the next time-slice after current active | 353 | * :2: HIGH = schedule VF in the next time-slice after current active |
| 354 | * time-slice completes if it has active work | 354 | * time-slice completes if it has active work |
| 355 | * | ||
| 356 | * _`GUC_KLV_VF_CFG_THRESHOLD_MULTI_LRC_COUNT` : 0x8A0D | ||
| 357 | * Given that multi-LRC contexts are incompatible with SRIOV scheduler | ||
| 358 | * groups and cause the latter to be turned off when registered with the | ||
| 359 | * GuC, this config allows the PF to set a threshold for multi-LRC context | ||
| 360 | * registrations by VFs to monitor their behavior. | ||
| 355 | */ | 361 | */ |
| 356 | 362 | ||
| 357 | #define GUC_KLV_VF_CFG_GGTT_START_KEY 0x0001 | 363 | #define GUC_KLV_VF_CFG_GGTT_START_KEY 0x0001 |
| @@ -410,6 +416,9 @@ enum { · 52 unmodified lines | |||
| 410 | #define GUC_SCHED_PRIORITY_NORMAL 1u | 416 | #define GUC_SCHED_PRIORITY_NORMAL 1u |
| 411 | #define GUC_SCHED_PRIORITY_HIGH 2u | 417 | #define GUC_SCHED_PRIORITY_HIGH 2u |
| 412 | 418 | ||
| 419 | #define GUC_KLV_VF_CFG_THRESHOLD_MULTI_LRC_COUNT_KEY 0x8a0d | ||
| 420 | #define GUC_KLV_VF_CFG_THRESHOLD_MULTI_LRC_COUNT_LEN 1u | ||
| 421 | |||
| 413 | /* | 422 | /* |
| 414 | * Workaround keys: | 423 | * Workaround keys: |
| 415 | */ | 424 | */ |
| @@ -0,0 +1,171 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | /* | ||
| 3 | * Copyright © 2025 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _ABI_GUC_LFD_ABI_H_ | ||
| 7 | #define _ABI_GUC_LFD_ABI_H_ | ||
| 8 | |||
| 9 | #include <linux/types.h> | ||
| 10 | |||
| 11 | #include "guc_lic_abi.h" | ||
| 12 | |||
| 13 | /* The current major version of GuC-Log-File format. */ | ||
| 14 | #define GUC_LFD_FORMAT_VERSION_MAJOR 0x0001 | ||
| 15 | /* The current minor version of GuC-Log-File format. */ | ||
| 16 | #define GUC_LFD_FORMAT_VERSION_MINOR 0x0000 | ||
| 17 | |||
| 18 | /** enum guc_lfd_type - Log format descriptor type */ | ||
| 19 | enum guc_lfd_type { | ||
| 20 | /** | ||
| 21 | * @GUC_LFD_TYPE_FW_REQUIRED_RANGE_START: Start of range for | ||
| 22 | * required LFDs from GuC | ||
| 23 | * @GUC_LFD_TYPE_FW_VERSION: GuC Firmware Version structure. | ||
| 24 | * @GUC_LFD_TYPE_GUC_DEVICE_ID: GuC microcontroller device ID. | ||
| 25 | * @GUC_LFD_TYPE_TSC_FREQUENCY: Frequency of GuC timestamps. | ||
| 26 | * @GUC_LFD_TYPE_GMD_ID: HW GMD ID. | ||
| 27 | * @GUC_LFD_TYPE_BUILD_PLATFORM_ID: GuC build platform ID. | ||
| 28 | * @GUC_LFD_TYPE_FW_REQUIRED_RANGE_END: End of range for | ||
| 29 | * required LFDs from GuC | ||
| 30 | */ | ||
| 31 | GUC_LFD_TYPE_FW_REQUIRED_RANGE_START = 0x1, | ||
| 32 | GUC_LFD_TYPE_FW_VERSION = 0x1, | ||
| 33 | GUC_LFD_TYPE_GUC_DEVICE_ID = 0x2, | ||
| 34 | GUC_LFD_TYPE_TSC_FREQUENCY = 0x3, | ||
| 35 | GUC_LFD_TYPE_GMD_ID = 0x4, | ||
| 36 | GUC_LFD_TYPE_BUILD_PLATFORM_ID = 0x5, | ||
| 37 | GUC_LFD_TYPE_FW_REQUIRED_RANGE_END = 0x1FFF, | ||
| 38 | |||
| 39 | /** | ||
| 40 | * @GUC_LFD_TYPE_FW_OPTIONAL_RANGE_START: Start of range for | ||
| 41 | * optional LFDs from GuC | ||
| 42 | * @GUC_LFD_TYPE_LOG_EVENTS_BUFFER: Log-event-entries buffer. | ||
| 43 | * @GUC_LFD_TYPE_FW_CRASH_DUMP: GuC generated crash-dump blob. | ||
| 44 | * @GUC_LFD_TYPE_FW_OPTIONAL_RANGE_END: End of range for | ||
| 45 | * optional LFDs from GuC | ||
| 46 | */ | ||
| 47 | GUC_LFD_TYPE_FW_OPTIONAL_RANGE_START = 0x2000, | ||
| 48 | GUC_LFD_TYPE_LOG_EVENTS_BUFFER = 0x2000, | ||
| 49 | GUC_LFD_TYPE_FW_CRASH_DUMP = 0x2001, | ||
| 50 | GUC_LFD_TYPE_FW_OPTIONAL_RANGE_END = 0x3FFF, | ||
| 51 | |||
| 52 | /** | ||
| 53 | * @GUC_LFD_TYPE_KMD_REQUIRED_RANGE_START: Start of range for | ||
| 54 | * required KMD LFDs | ||
| 55 | * @GUC_LFD_TYPE_OS_ID: An identifier for the OS. | ||
| 56 | * @GUC_LFD_TYPE_KMD_REQUIRED_RANGE_END: End of this range for | ||
| 57 | * required KMD LFDs | ||
| 58 | */ | ||
| 59 | GUC_LFD_TYPE_KMD_REQUIRED_RANGE_START = 0x4000, | ||
| 60 | GUC_LFD_TYPE_OS_ID = 0x4000, | ||
| 61 | GUC_LFD_TYPE_KMD_REQUIRED_RANGE_END = 0x5FFF, | ||
| 62 | |||
| 63 | /** | ||
| 64 | * @GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_START: Start of range for | ||
| 65 | * optional KMD LFDs | ||
| 66 | * @GUC_LFD_TYPE_BINARY_SCHEMA_FORMAT: Binary representation of | ||
| 67 | * GuC log-events schema. | ||
| 68 | * @GUC_LFD_TYPE_HOST_COMMENT: ASCII string containing comments | ||
| 69 | * from the host/KMD. | ||
| 70 | * @GUC_LFD_TYPE_TIMESTAMP_ANCHOR: A timestamp anchor, to convert | ||
| 71 | * between host and GuC timestamp. | ||
| 72 | * @GUC_LFD_TYPE_TIMESTAMP_ANCHOR_CONFIG: Timestamp anchor | ||
| 73 | * configuration, definition of timestamp frequency and bit width. | ||
| 74 | * @GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_END: End of this range for | ||
| 75 | * optional KMD LFDs | ||
| 76 | */ | ||
| 77 | GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_START = 0x6000, | ||
| 78 | GUC_LFD_TYPE_BINARY_SCHEMA_FORMAT = 0x6000, | ||
| 79 | GUC_LFD_TYPE_HOST_COMMENT = 0x6001, | ||
| 80 | GUC_LFD_TYPE_TIMESTAMP_ANCHOR = 0x6002, | ||
| 81 | GUC_LFD_TYPE_TIMESTAMP_ANCHOR_CONFIG = 0x6003, | ||
| 82 | GUC_LFD_TYPE_KMD_OPTIONAL_RANGE_END = 0x7FFF, | ||
| 83 | |||
| 84 | /* | ||
| 85 | * @GUC_LFD_TYPE_RESERVED_RANGE_START: Start of reserved range | ||
| 86 | * @GUC_LFD_TYPE_RESERVED_RANGE_END: End of reserved range | ||
| 87 | */ | ||
| 88 | GUC_LFD_TYPE_RESERVED_RANGE_START = 0x8000, | ||
| 89 | GUC_LFD_TYPE_RESERVED_RANGE_END = 0xFFFF, | ||
| 90 | }; | ||
| 91 | |||
| 92 | /** enum guc_lfd_os_type - OS Type LFD-ID */ | ||
| 93 | enum guc_lfd_os_type { | ||
| 94 | /** @GUC_LFD_OS_TYPE_OSID_WIN: Windows OS */ | ||
| 95 | GUC_LFD_OS_TYPE_OSID_WIN = 0x1, | ||
| 96 | /** @GUC_LFD_OS_TYPE_OSID_LIN: Linux OS */ | ||
| 97 | GUC_LFD_OS_TYPE_OSID_LIN = 0x2, | ||
| 98 | /** @GUC_LFD_OS_TYPE_OSID_VMW: VMWare OS */ | ||
| 99 | GUC_LFD_OS_TYPE_OSID_VMW = 0x3, | ||
| 100 | /** @GUC_LFD_OS_TYPE_OSID_OTHER: Other */ | ||
| 101 | GUC_LFD_OS_TYPE_OSID_OTHER = 0x4, | ||
| 102 | }; | ||
| 103 | |||
| 104 | /** struct guc_lfd_data - A generic header structure for all LFD blocks */ | ||
| 105 | struct guc_lfd_data { | ||
| 106 | /** @header: A 32 bits dword, contains multiple bit fields */ | ||
| 107 | u32 header; | ||
| 108 | /* LFD type. See guc_lfd_type */ | ||
| 109 | #define GUC_LFD_DATA_HEADER_MASK_TYPE GENMASK(31, 16) | ||
| 110 | #define GUC_LFD_DATA_HEADER_MASK_MAGIC GENMASK(15, 0) | ||
| 111 | |||
| 112 | /** @data_count: Number of dwords the `data` field contains. */ | ||
| 113 | u32 data_count; | ||
| 114 | /** @data: Data defined by GUC_LFD_DATA_HEADER_MASK_TYPE */ | ||
| 115 | u32 data[] __counted_by(data_count); | ||
| 116 | } __packed; | ||
| 117 | |||
| 118 | /** | ||
| 119 | * struct guc_lfd_data_log_events_buf - GuC Log Events Buffer. | ||
| 120 | * This is optional fw LFD data | ||
| 121 | */ | ||
| 122 | struct guc_lfd_data_log_events_buf { | ||
| 123 | /** | ||
| 124 | * @log_events_format_version: version of GuC log format of buffer | ||
| 125 | */ | ||
| 126 | u32 log_events_format_version; | ||
| 127 | /** | ||
| 128 | * @log_event: The log event data. | ||
| 129 | * Size in dwords is LFD block size - 1. | ||
| 130 | */ | ||
| 131 | u32 log_event[]; | ||
| 132 | } __packed; | ||
| 133 | |||
| 134 | /** struct guc_lfd_data_os_info - OS Version Information. */ | ||
| 135 | struct guc_lfd_data_os_info { | ||
| 136 | /** | ||
| 137 | * @os_id: enum values to identify the OS brand. | ||
| 138 | * See guc_lfd_os_type for the range of types | ||
| 139 | */ | ||
| 140 | u32 os_id; | ||
| 141 | /** | ||
| 142 | * @build_version: ASCII string containing OS build version | ||
| 143 | * information based on os_id. String is padded with null | ||
| 144 | * characters to ensure its DWORD aligned. | ||
| 145 | * Size in dwords is LFD block size - 1. | ||
| 146 | */ | ||
| 147 | char build_version[]; | ||
| 148 | } __packed; | ||
| 149 | |||
| 150 | /** | ||
| 151 | * struct guc_logfile_header - Header of GuC Log Streaming-LFD-File Format. | ||
| 152 | * This structure encapsulates the layout of the guc-log-file format | ||
| 153 | */ | ||
| 154 | struct guc_lfd_file_header { | ||
| 155 | /** | ||
| 156 | * @magic: A magic number set by producer of a GuC log file to | ||
| 157 | * identify that file is a valid guc-log-file containing a stream | ||
| 158 | * of LFDs. | ||
| 159 | */ | ||
| 160 | u64 magic; | ||
| 161 | /** @version: Version of this file format layout */ | ||
| 162 | u32 version; | ||
| 163 | #define GUC_LFD_FILE_HEADER_VERSION_MASK_MAJOR GENMASK(31, 16) | ||
| 164 | #define GUC_LFD_FILE_HEADER_VERSION_MASK_MINOR GENMASK(15, 0) | ||
| 165 | |||
| 166 | /** @stream: A stream of one or more guc_lfd_data LFD blocks | ||
| 167 | */ | ||
| 168 | u32 stream[]; | ||
| 169 | } __packed; | ||
| 170 | |||
| 171 | #endif | ||
| @@ -0,0 +1,77 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | /* | ||
| 3 | * Copyright © 2025 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _ABI_GUC_LIC_ABI_H_ | ||
| 7 | #define _ABI_GUC_LIC_ABI_H_ | ||
| 8 | |||
| 9 | #include <linux/types.h> | ||
| 10 | |||
| 11 | /** | ||
| 12 | * enum guc_lic_type - Log Init Config KLV IDs. | ||
| 13 | */ | ||
| 14 | enum guc_lic_type { | ||
| 15 | /** | ||
| 16 | * @GUC_LIC_TYPE_GUC_SW_VERSION: GuC firmware version. Value | ||
| 17 | * is a 32 bit number represented by guc_sw_version. | ||
| 18 | */ | ||
| 19 | GUC_LIC_TYPE_GUC_SW_VERSION = 0x1, | ||
| 20 | /** | ||
| 21 | * @GUC_LIC_TYPE_GUC_DEVICE_ID: GuC device id. Value is a 32 | ||
| 22 | * bit. | ||
| 23 | */ | ||
| 24 | GUC_LIC_TYPE_GUC_DEVICE_ID = 0x2, | ||
| 25 | /** | ||
| 26 | * @GUC_LIC_TYPE_TSC_FREQUENCY: GuC timestamp counter | ||
| 27 | * frequency. Value is a 32 bit number representing frequency in | ||
| 28 | * kHz. This timestamp is utilized in log entries, timer and | ||
| 29 | * for engine utilization tracking. | ||
| 30 | */ | ||
| 31 | GUC_LIC_TYPE_TSC_FREQUENCY = 0x3, | ||
| 32 | /** | ||
| 33 | * @GUC_LIC_TYPE_GMD_ID: HW GMD ID. Value is a 32 bit number | ||
| 34 | * representing graphics, media and display HW architecture IDs. | ||
| 35 | */ | ||
| 36 | GUC_LIC_TYPE_GMD_ID = 0x4, | ||
| 37 | /** | ||
| 38 | * @GUC_LIC_TYPE_BUILD_PLATFORM_ID: GuC build platform ID. | ||
| 39 | * Value is 32 bits. | ||
| 40 | */ | ||
| 41 | GUC_LIC_TYPE_BUILD_PLATFORM_ID = 0x5, | ||
| 42 | }; | ||
| 43 | |||
| 44 | /** | ||
| 45 | * struct guc_lic - GuC LIC (Log-Init-Config) structure. | ||
| 46 | * | ||
| 47 | * This is populated by the GUC at log init time and is located in the log | ||
| 48 | * buffer memory allocation. | ||
| 49 | */ | ||
| 50 | struct guc_lic { | ||
| 51 | /** | ||
| 52 | * @magic: A magic number set by GuC to identify that this | ||
| 53 | * structure contains valid information: magic = GUC_LIC_MAGIC. | ||
| 54 | */ | ||
| 55 | u32 magic; | ||
| 56 | #define GUC_LIC_MAGIC 0x8086900D | ||
| 57 | /** | ||
| 58 | * @version: The version of the this structure. | ||
| 59 | * Major and minor version number are represented as bit fields. | ||
| 60 | */ | ||
| 61 | u32 version; | ||
| 62 | #define GUC_LIC_VERSION_MASK_MAJOR GENMASK(31, 16) | ||
| 63 | #define GUC_LIC_VERSION_MASK_MINOR GENMASK(15, 0) | ||
| 64 | |||
| 65 | #define GUC_LIC_VERSION_MAJOR 1u | ||
| 66 | #define GUC_LIC_VERSION_MINOR 0u | ||
| 67 | |||
| 68 | /** @data_count: Number of dwords the `data` array contains. */ | ||
| 69 | u32 data_count; | ||
| 70 | /** | ||
| 71 | * @data: Array of dwords representing a list of LIC KLVs of | ||
| 72 | * type guc_klv_generic with keys represented by guc_lic_type | ||
| 73 | */ | ||
| 74 | u32 data[] __counted_by(data_count); | ||
| 75 | } __packed; | ||
| 76 | |||
| 77 | #endif | ||
| @@ -8,11 +8,45 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
| 10 | 10 | ||
| 11 | /** | ||
| 12 | * DOC: GuC Log buffer Layout | ||
| 13 | * | ||
| 14 | * The in-memory log buffer layout is as follows:: | ||
| 15 | * | ||
| 16 | * +===============================+ 0000h | ||
| 17 | * | Crash dump state header | ^ | ||
| 18 | * +-------------------------------+ 32B | | ||
| 19 | * | Debug state header | | | ||
| 20 | * +-------------------------------+ 64B 4KB | ||
| 21 | * | Capture state header | | | ||
| 22 | * +-------------------------------+ 96B | | ||
| 23 | * | | v | ||
| 24 | * +===============================+ <--- EVENT_DATA_OFFSET | ||
| 25 | * | Event logs(raw data) | ^ | ||
| 26 | * | | | | ||
| 27 | * | | EVENT_DATA_BUFFER_SIZE | ||
| 28 | * | | | | ||
| 29 | * | | v | ||
| 30 | * +===============================+ <--- CRASH_DUMP_OFFSET | ||
| 31 | * | Crash Dump(raw data) | ^ | ||
| 32 | * | | | | ||
| 33 | * | | CRASH_DUMP_BUFFER_SIZE | ||
| 34 | * | | | | ||
| 35 | * | | v | ||
| 36 | * +===============================+ <--- STATE_CAPTURE_OFFSET | ||
| 37 | * | Error state capture(raw data) | ^ | ||
| 38 | * | | | | ||
| 39 | * | | STATE_CAPTURE_BUFFER_SIZE | ||
| 40 | * | | | | ||
| 41 | * | | v | ||
| 42 | * +===============================+ Total: GUC_LOG_SIZE | ||
| 43 | */ | ||
| 44 | |||
| 11 | /* GuC logging buffer types */ | 45 | /* GuC logging buffer types */ |
| 12 | enum guc_log_buffer_type { | 46 | enum guc_log_type { |
| 13 | GUC_LOG_BUFFER_CRASH_DUMP, | 47 | GUC_LOG_TYPE_EVENT_DATA, |
| 14 | GUC_LOG_BUFFER_DEBUG, | 48 | GUC_LOG_TYPE_CRASH_DUMP, |
| 15 | GUC_LOG_BUFFER_CAPTURE, | 49 | GUC_LOG_TYPE_STATE_CAPTURE, |
| 16 | }; | 50 | }; |
| 17 | 51 | ||
| 18 | #define GUC_LOG_BUFFER_TYPE_MAX 3 | 52 | #define GUC_LOG_BUFFER_TYPE_MAX 3 |
| @@ -210,10 +210,11 @@ static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb, · 209 unmodified lines | |||
| 210 | /* TODO: Consider sharing framebuffer mapping? | 210 | /* TODO: Consider sharing framebuffer mapping? |
| 211 | * embed i915_vma inside intel_framebuffer | 211 | * embed i915_vma inside intel_framebuffer |
| 212 | */ | 212 | */ |
| 213 | xe_pm_runtime_get_noresume(xe); | 213 | guard(xe_pm_runtime_noresume)(xe); |
| 214 | ret = mutex_lock_interruptible(&ggtt->lock); | 214 | ACQUIRE(mutex_intr, lock)(&ggtt->lock); |
| 215 | ret = ACQUIRE_ERR(mutex_intr, &lock); | ||
| 215 | if (ret) | 216 | if (ret) |
| 216 | goto out; | 217 | return ret; |
| 217 | 218 | ||
| 218 | align = XE_PAGE_SIZE; | 219 | align = XE_PAGE_SIZE; |
| 219 | if (xe_bo_is_vram(bo) && ggtt->flags & XE_GGTT_FLAGS_64K) | 220 | if (xe_bo_is_vram(bo) && ggtt->flags & XE_GGTT_FLAGS_64K) |
| @@ -223,15 +224,13 @@ static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb, · 3 unmodified lines | |||
| 223 | vma->node = bo->ggtt_node[tile0->id]; | 224 | vma->node = bo->ggtt_node[tile0->id]; |
| 224 | } else if (view->type == I915_GTT_VIEW_NORMAL) { | 225 | } else if (view->type == I915_GTT_VIEW_NORMAL) { |
| 225 | vma->node = xe_ggtt_node_init(ggtt); | 226 | vma->node = xe_ggtt_node_init(ggtt); |
| 226 | if (IS_ERR(vma->node)) { | 227 | if (IS_ERR(vma->node)) |
| 227 | ret = PTR_ERR(vma->node); | 228 | return PTR_ERR(vma->node); |
| 228 | goto out_unlock; | ||
| 229 | } | ||
| 230 | 229 | ||
| 231 | ret = xe_ggtt_node_insert_locked(vma->node, xe_bo_size(bo), align, 0); | 230 | ret = xe_ggtt_node_insert_locked(vma->node, xe_bo_size(bo), align, 0); |
| 232 | if (ret) { | 231 | if (ret) { |
| 233 | xe_ggtt_node_fini(vma->node); | 232 | xe_ggtt_node_fini(vma->node); |
| 234 | goto out_unlock; | 233 | return ret; |
| 235 | } | 234 | } |
| 236 | 235 | ||
| 237 | xe_ggtt_map_bo(ggtt, vma->node, bo, xe->pat.idx[XE_CACHE_NONE]); | 236 | xe_ggtt_map_bo(ggtt, vma->node, bo, xe->pat.idx[XE_CACHE_NONE]); |
| @@ -245,13 +244,13 @@ static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb, · 7 unmodified lines | |||
| 245 | vma->node = xe_ggtt_node_init(ggtt); | 244 | vma->node = xe_ggtt_node_init(ggtt); |
| 246 | if (IS_ERR(vma->node)) { | 245 | if (IS_ERR(vma->node)) { |
| 247 | ret = PTR_ERR(vma->node); | 246 | ret = PTR_ERR(vma->node); |
| 248 | goto out_unlock; | 247 | return ret; |
| 249 | } | 248 | } |
| 250 | 249 | ||
| 251 | ret = xe_ggtt_node_insert_locked(vma->node, size, align, 0); | 250 | ret = xe_ggtt_node_insert_locked(vma->node, size, align, 0); |
| 252 | if (ret) { | 251 | if (ret) { |
| 253 | xe_ggtt_node_fini(vma->node); | 252 | xe_ggtt_node_fini(vma->node); |
| 254 | goto out_unlock; | 253 | return ret; |
| 255 | } | 254 | } |
| 256 | 255 | ||
| 257 | ggtt_ofs = vma->node->base.start; | 256 | ggtt_ofs = vma->node->base.start; |
| @@ -265,10 +264,6 @@ static int __xe_pin_fb_vma_ggtt(const struct intel_framebuffer *fb, · 7 unmodified lines | |||
| 265 | rot_info->plane[i].dst_stride); | 264 | rot_info->plane[i].dst_stride); |
| 266 | } | 265 | } |
| 267 | 266 | ||
| 268 | out_unlock: | ||
| 269 | mutex_unlock(&ggtt->lock); | ||
| 270 | out: | ||
| 271 | xe_pm_runtime_put(xe); | ||
| 272 | return ret; | 267 | return ret; |
| 273 | } | 268 | } |
| 274 | 269 | ||
| @@ -38,8 +38,6 @@ static bool intel_hdcp_gsc_check_status(struct drm_device *drm) · 37 unmodified lines | |||
| 38 | struct xe_tile *tile = xe_device_get_root_tile(xe); | 38 | struct xe_tile *tile = xe_device_get_root_tile(xe); |
| 39 | struct xe_gt *gt = tile->media_gt; | 39 | struct xe_gt *gt = tile->media_gt; |
| 40 | struct xe_gsc *gsc = >->uc.gsc; | 40 | struct xe_gsc *gsc = >->uc.gsc; |
| 41 | bool ret = true; | ||
| 42 | unsigned int fw_ref; | ||
| 43 | 41 | ||
| 44 | if (!gsc || !xe_uc_fw_is_enabled(&gsc->fw)) { | 42 | if (!gsc || !xe_uc_fw_is_enabled(&gsc->fw)) { |
| 45 | drm_dbg_kms(&xe->drm, | 43 | drm_dbg_kms(&xe->drm, |
| @@ -47,22 +45,15 @@ static bool intel_hdcp_gsc_check_status(struct drm_device *drm) · 1 unmodified line | |||
| 47 | return false; | 45 | return false; |
| 48 | } | 46 | } |
| 49 | 47 | ||
| 50 | xe_pm_runtime_get(xe); | 48 | guard(xe_pm_runtime)(xe); |
| 51 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC); | 49 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC); |
| 52 | if (!fw_ref) { | 50 | if (!fw_ref.domains) { |
| 53 | drm_dbg_kms(&xe->drm, | 51 | drm_dbg_kms(&xe->drm, |
| 54 | "failed to get forcewake to check proxy status\n"); | 52 | "failed to get forcewake to check proxy status\n"); |
| 55 | ret = false; | 53 | return false; |
| 56 | goto out; | ||
| 57 | } | 54 | } |
| 58 | 55 | ||
| 59 | if (!xe_gsc_proxy_init_done(gsc)) | 56 | return xe_gsc_proxy_init_done(gsc); |
| 60 | ret = false; | ||
| 61 | |||
| 62 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 63 | out: | ||
| 64 | xe_pm_runtime_put(xe); | ||
| 65 | return ret; | ||
| 66 | } | 57 | } |
| 67 | 58 | ||
| 68 | /*This function helps allocate memory for the command that we will send to gsc cs */ | 59 | /*This function helps allocate memory for the command that we will send to gsc cs */ |
| @@ -168,17 +159,15 @@ static ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_contex · 99 unmodified lines | |||
| 168 | u32 addr_out_off, addr_in_wr_off = 0; | 159 | u32 addr_out_off, addr_in_wr_off = 0; |
| 169 | int ret, tries = 0; | 160 | int ret, tries = 0; |
| 170 | 161 | ||
| 171 | if (msg_in_len > max_msg_size || msg_out_len > max_msg_size) { | 162 | if (msg_in_len > max_msg_size || msg_out_len > max_msg_size) |
| 172 | ret = -ENOSPC; | 163 | return -ENOSPC; |
| 173 | goto out; | ||
| 174 | } | ||
| 175 | 164 | ||
| 176 | msg_size_in = msg_in_len + HDCP_GSC_HEADER_SIZE; | 165 | msg_size_in = msg_in_len + HDCP_GSC_HEADER_SIZE; |
| 177 | msg_size_out = msg_out_len + HDCP_GSC_HEADER_SIZE; | 166 | msg_size_out = msg_out_len + HDCP_GSC_HEADER_SIZE; |
| 178 | addr_out_off = PAGE_SIZE; | 167 | addr_out_off = PAGE_SIZE; |
| 179 | 168 | ||
| 180 | host_session_id = xe_gsc_create_host_session_id(); | 169 | host_session_id = xe_gsc_create_host_session_id(); |
| 181 | xe_pm_runtime_get_noresume(xe); | 170 | guard(xe_pm_runtime_noresume)(xe); |
| 182 | addr_in_wr_off = xe_gsc_emit_header(xe, &gsc_context->hdcp_bo->vmap, | 171 | addr_in_wr_off = xe_gsc_emit_header(xe, &gsc_context->hdcp_bo->vmap, |
| 183 | addr_in_wr_off, HECI_MEADDRESS_HDCP, | 172 | addr_in_wr_off, HECI_MEADDRESS_HDCP, |
| 184 | host_session_id, msg_in_len); | 173 | host_session_id, msg_in_len); |
| @@ -203,14 +192,12 @@ static ssize_t intel_hdcp_gsc_msg_send(struct intel_hdcp_gsc_context *gsc_contex · 18 unmodified lines | |||
| 203 | } while (++tries < 20); | 192 | } while (++tries < 20); |
| 204 | 193 | ||
| 205 | if (ret) | 194 | if (ret) |
| 206 | goto out; | 195 | return ret; |
| 207 | 196 | ||
| 208 | xe_map_memcpy_from(xe, msg_out, &gsc_context->hdcp_bo->vmap, | 197 | xe_map_memcpy_from(xe, msg_out, &gsc_context->hdcp_bo->vmap, |
| 209 | addr_out_off + HDCP_GSC_HEADER_SIZE, | 198 | addr_out_off + HDCP_GSC_HEADER_SIZE, |
| 210 | msg_out_len); | 199 | msg_out_len); |
| 211 | 200 | ||
| 212 | out: | ||
| 213 | xe_pm_runtime_put(xe); | ||
| 214 | return ret; | 201 | return ret; |
| 215 | } | 202 | } |
| 216 | 203 | ||
| @@ -47,6 +47,7 @@ · 46 unmodified lines | |||
| 47 | 47 | ||
| 48 | #define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|((len)-2)) | 48 | #define GFX_OP_PIPE_CONTROL(len) ((0x3<<29)|(0x3<<27)|(0x2<<24)|((len)-2)) |
| 49 | 49 | ||
| 50 | #define PIPE_CONTROL0_QUEUE_DRAIN_MODE BIT(12) | ||
| 50 | #define PIPE_CONTROL0_L3_READ_ONLY_CACHE_INVALIDATE BIT(10) /* gen12 */ | 51 | #define PIPE_CONTROL0_L3_READ_ONLY_CACHE_INVALIDATE BIT(10) /* gen12 */ |
| 51 | #define PIPE_CONTROL0_HDC_PIPELINE_FLUSH BIT(9) /* gen12 */ | 52 | #define PIPE_CONTROL0_HDC_PIPELINE_FLUSH BIT(9) /* gen12 */ |
| 52 | 53 | ||
| @@ -227,6 +227,9 @@ · 226 unmodified lines | |||
| 227 | 227 | ||
| 228 | #define MIRROR_FUSE1 XE_REG(0x911c) | 228 | #define MIRROR_FUSE1 XE_REG(0x911c) |
| 229 | 229 | ||
| 230 | #define FUSE2 XE_REG(0x9120) | ||
| 231 | #define PRODUCTION_HW REG_BIT(2) | ||
| 232 | |||
| 230 | #define MIRROR_L3BANK_ENABLE XE_REG(0x9130) | 233 | #define MIRROR_L3BANK_ENABLE XE_REG(0x9130) |
| 231 | #define XE3_L3BANK_ENABLE REG_GENMASK(31, 0) | 234 | #define XE3_L3BANK_ENABLE REG_GENMASK(31, 0) |
| 232 | 235 | ||
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #define XELPG_GGTT_PTE_PAT0 BIT_ULL(52) | 9 | #define XELPG_GGTT_PTE_PAT0 BIT_ULL(52) |
| 10 | #define XELPG_GGTT_PTE_PAT1 BIT_ULL(53) | 10 | #define XELPG_GGTT_PTE_PAT1 BIT_ULL(53) |
| 11 | 11 | ||
| 12 | #define XE_PTE_ADDR_MASK GENMASK_ULL(51, 12) | ||
| 12 | #define GGTT_PTE_VFID GENMASK_ULL(11, 2) | 13 | #define GGTT_PTE_VFID GENMASK_ULL(11, 2) |
| 13 | 14 | ||
| 14 | #define GUC_GGTT_TOP 0xFEE00000 | 15 | #define GUC_GGTT_TOP 0xFEE00000 |
| @@ -90,6 +90,9 @@ · 89 unmodified lines | |||
| 90 | #define GUC_SEND_INTERRUPT XE_REG(0xc4c8) | 90 | #define GUC_SEND_INTERRUPT XE_REG(0xc4c8) |
| 91 | #define GUC_SEND_TRIGGER REG_BIT(0) | 91 | #define GUC_SEND_TRIGGER REG_BIT(0) |
| 92 | 92 | ||
| 93 | #define GUC_INTR_CHICKEN XE_REG(0xc50c) | ||
| 94 | #define DISABLE_SIGNALING_ENGINES REG_BIT(1) | ||
| 95 | |||
| 93 | #define GUC_BCS_RCS_IER XE_REG(0xc550) | 96 | #define GUC_BCS_RCS_IER XE_REG(0xc550) |
| 94 | #define GUC_VCS2_VCS1_IER XE_REG(0xc554) | 97 | #define GUC_VCS2_VCS1_IER XE_REG(0xc554) |
| 95 | #define GUC_WD_VECS_IER XE_REG(0xc558) | 98 | #define GUC_WD_VECS_IER XE_REG(0xc558) |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | |||
| 20 | #define GU_MISC_IRQ REG_BIT(29) | 20 | #define GU_MISC_IRQ REG_BIT(29) |
| 21 | #define ERROR_IRQ(x) REG_BIT(26 + (x)) | 21 | #define ERROR_IRQ(x) REG_BIT(26 + (x)) |
| 22 | #define DISPLAY_IRQ REG_BIT(16) | 22 | #define DISPLAY_IRQ REG_BIT(16) |
| 23 | #define SOC_H2DMEMINT_IRQ REG_BIT(13) | ||
| 23 | #define I2C_IRQ REG_BIT(12) | 24 | #define I2C_IRQ REG_BIT(12) |
| 24 | #define GT_DW_IRQ(x) REG_BIT(x) | 25 | #define GT_DW_IRQ(x) REG_BIT(x) |
| 25 | 26 | ||
| @@ -0,0 +1,21 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | /* | ||
| 3 | * Copyright © 2025 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _XE_MERT_REGS_H_ | ||
| 7 | #define _XE_MERT_REGS_H_ | ||
| 8 | |||
| 9 | #include "regs/xe_reg_defs.h" | ||
| 10 | |||
| 11 | #define MERT_LMEM_CFG XE_REG(0x1448b0) | ||
| 12 | |||
| 13 | #define MERT_TLB_CT_INTR_ERR_ID_PORT XE_REG(0x145190) | ||
| 14 | #define MERT_TLB_CT_VFID_MASK REG_GENMASK(16, 9) | ||
| 15 | #define MERT_TLB_CT_ERROR_MASK REG_GENMASK(5, 0) | ||
| 16 | #define MERT_TLB_CT_LMTT_FAULT 0x05 | ||
| 17 | |||
| 18 | #define MERT_TLB_INV_DESC_A XE_REG(0x14cf7c) | ||
| 19 | #define MERT_TLB_INV_DESC_A_VALID REG_BIT(0) | ||
| 20 | |||
| 21 | #endif /* _XE_MERT_REGS_H_ */ | ||
| @@ -100,4 +100,21 @@ · 99 unmodified lines | |||
| 100 | #define OAM_COMPRESSION_T3_CONTROL XE_REG(0x1c2e00) | 100 | #define OAM_COMPRESSION_T3_CONTROL XE_REG(0x1c2e00) |
| 101 | #define OAM_LAT_MEASURE_ENABLE REG_BIT(4) | 101 | #define OAM_LAT_MEASURE_ENABLE REG_BIT(4) |
| 102 | 102 | ||
| 103 | /* Actual address is MEDIA_GT_GSI_OFFSET + the base addr below */ | ||
| 104 | #define XE_OAM_SAG_BASE 0x13000 | ||
| 105 | #define XE_OAM_SCMI_0_BASE 0x14000 | ||
| 106 | #define XE_OAM_SCMI_1_BASE 0x14800 | ||
| 107 | #define XE_OAM_SAG_BASE_ADJ (MEDIA_GT_GSI_OFFSET + XE_OAM_SAG_BASE) | ||
| 108 | #define XE_OAM_SCMI_0_BASE_ADJ (MEDIA_GT_GSI_OFFSET + XE_OAM_SCMI_0_BASE) | ||
| 109 | #define XE_OAM_SCMI_1_BASE_ADJ (MEDIA_GT_GSI_OFFSET + XE_OAM_SCMI_1_BASE) | ||
| 110 | |||
| 111 | #define OAMERT_CONTROL XE_REG(0x1453a0) | ||
| 112 | #define OAMERT_DEBUG XE_REG(0x1453a4) | ||
| 113 | #define OAMERT_STATUS XE_REG(0x1453a8) | ||
| 114 | #define OAMERT_HEAD_POINTER XE_REG(0x1453ac) | ||
| 115 | #define OAMERT_TAIL_POINTER XE_REG(0x1453b0) | ||
| 116 | #define OAMERT_BUFFER XE_REG(0x1453b4) | ||
| 117 | #define OAMERT_CONTEXT_CONTROL XE_REG(0x1453c8) | ||
| 118 | #define OAMERT_MMIO_TRG XE_REG(0x1453cc) | ||
| 119 | |||
| 103 | #endif | 120 | #endif |
| @@ -78,6 +78,24 @@ static void pick_arg_example(struct kunit *test) · 77 unmodified lines | |||
| 78 | #undef buz | 78 | #undef buz |
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | static void if_args_example(struct kunit *test) | ||
| 82 | { | ||
| 83 | enum { Z = 1, Q }; | ||
| 84 | |||
| 85 | #define foo X, Y | ||
| 86 | #define bar IF_ARGS(Z, Q, foo) | ||
| 87 | #define buz IF_ARGS(Z, Q, DROP_FIRST_ARG(FIRST_ARG(foo))) | ||
| 88 | |||
| 89 | KUNIT_EXPECT_EQ(test, bar, Z); | ||
| 90 | KUNIT_EXPECT_EQ(test, buz, Q); | ||
| 91 | KUNIT_EXPECT_STREQ(test, __stringify(bar), "Z"); | ||
| 92 | KUNIT_EXPECT_STREQ(test, __stringify(buz), "Q"); | ||
| 93 | |||
| 94 | #undef foo | ||
| 95 | #undef bar | ||
| 96 | #undef buz | ||
| 97 | } | ||
| 98 | |||
| 81 | static void sep_comma_example(struct kunit *test) | 99 | static void sep_comma_example(struct kunit *test) |
| 82 | { | 100 | { |
| 83 | #define foo(f) f(X) f(Y) f(Z) f(Q) | 101 | #define foo(f) f(X) f(Y) f(Z) f(Q) |
| @@ -198,6 +216,40 @@ static void last_arg_test(struct kunit *test) · 114 unmodified lines | |||
| 198 | KUNIT_EXPECT_STREQ(test, __stringify(LAST_ARG(MAX_ARGS)), "-12"); | 216 | KUNIT_EXPECT_STREQ(test, __stringify(LAST_ARG(MAX_ARGS)), "-12"); |
| 199 | } | 217 | } |
| 200 | 218 | ||
| 219 | static void if_args_test(struct kunit *test) | ||
| 220 | { | ||
| 221 | bool with_args = true; | ||
| 222 | bool no_args = false; | ||
| 223 | enum { X = 100 }; | ||
| 224 | |||
| 225 | KUNIT_EXPECT_TRUE(test, IF_ARGS(true, false, FOO_ARGS)); | ||
| 226 | KUNIT_EXPECT_FALSE(test, IF_ARGS(true, false, NO_ARGS)); | ||
| 227 | |||
| 228 | KUNIT_EXPECT_TRUE(test, CONCATENATE(IF_ARGS(with, no, FOO_ARGS), _args)); | ||
| 229 | KUNIT_EXPECT_FALSE(test, CONCATENATE(IF_ARGS(with, no, NO_ARGS), _args)); | ||
| 230 | |||
| 231 | KUNIT_EXPECT_STREQ(test, __stringify(IF_ARGS(yes, no, FOO_ARGS)), "yes"); | ||
| 232 | KUNIT_EXPECT_STREQ(test, __stringify(IF_ARGS(yes, no, NO_ARGS)), "no"); | ||
| 233 | |||
| 234 | KUNIT_EXPECT_EQ(test, IF_ARGS(CALL_ARGS(COUNT_ARGS, FOO_ARGS), -1, FOO_ARGS), 4); | ||
| 235 | KUNIT_EXPECT_EQ(test, IF_ARGS(CALL_ARGS(COUNT_ARGS, FOO_ARGS), -1, NO_ARGS), -1); | ||
| 236 | KUNIT_EXPECT_EQ(test, IF_ARGS(CALL_ARGS(COUNT_ARGS, NO_ARGS), -1, FOO_ARGS), 0); | ||
| 237 | KUNIT_EXPECT_EQ(test, IF_ARGS(CALL_ARGS(COUNT_ARGS, NO_ARGS), -1, NO_ARGS), -1); | ||
| 238 | |||
| 239 | KUNIT_EXPECT_EQ(test, | ||
| 240 | CALL_ARGS(FIRST_ARG, | ||
| 241 | CALL_ARGS(CONCATENATE, IF_ARGS(FOO, MAX, FOO_ARGS), _ARGS)), X); | ||
| 242 | KUNIT_EXPECT_EQ(test, | ||
| 243 | CALL_ARGS(FIRST_ARG, | ||
| 244 | CALL_ARGS(CONCATENATE, IF_ARGS(FOO, MAX, NO_ARGS), _ARGS)), -1); | ||
| 245 | KUNIT_EXPECT_EQ(test, | ||
| 246 | CALL_ARGS(COUNT_ARGS, | ||
| 247 | CALL_ARGS(CONCATENATE, IF_ARGS(FOO, MAX, FOO_ARGS), _ARGS)), 4); | ||
| 248 | KUNIT_EXPECT_EQ(test, | ||
| 249 | CALL_ARGS(COUNT_ARGS, | ||
| 250 | CALL_ARGS(CONCATENATE, IF_ARGS(FOO, MAX, NO_ARGS), _ARGS)), 12); | ||
| 251 | } | ||
| 252 | |||
| 201 | static struct kunit_case args_tests[] = { | 253 | static struct kunit_case args_tests[] = { |
| 202 | KUNIT_CASE(count_args_test), | 254 | KUNIT_CASE(count_args_test), |
| 203 | KUNIT_CASE(call_args_example), | 255 | KUNIT_CASE(call_args_example), |
| @@ -209,6 +261,8 @@ static struct kunit_case args_tests[] = { · 5 unmodified lines | |||
| 209 | KUNIT_CASE(last_arg_example), | 261 | KUNIT_CASE(last_arg_example), |
| 210 | KUNIT_CASE(last_arg_test), | 262 | KUNIT_CASE(last_arg_test), |
| 211 | KUNIT_CASE(pick_arg_example), | 263 | KUNIT_CASE(pick_arg_example), |
| 264 | KUNIT_CASE(if_args_example), | ||
| 265 | KUNIT_CASE(if_args_test), | ||
| 212 | KUNIT_CASE(sep_comma_example), | 266 | KUNIT_CASE(sep_comma_example), |
| 213 | {} | 267 | {} |
| 214 | }; | 268 | }; |
| @@ -185,8 +185,7 @@ static int ccs_test_run_device(struct xe_device *xe) · 184 unmodified lines | |||
| 185 | return 0; | 185 | return 0; |
| 186 | } | 186 | } |
| 187 | 187 | ||
| 188 | xe_pm_runtime_get(xe); | 188 | guard(xe_pm_runtime)(xe); |
| 189 | |||
| 190 | for_each_tile(tile, xe, id) { | 189 | for_each_tile(tile, xe, id) { |
| 191 | /* For igfx run only for primary tile */ | 190 | /* For igfx run only for primary tile */ |
| 192 | if (!IS_DGFX(xe) && id > 0) | 191 | if (!IS_DGFX(xe) && id > 0) |
| @@ -194,8 +193,6 @@ static int ccs_test_run_device(struct xe_device *xe) · 1 unmodified line | |||
| 194 | ccs_test_run_tile(xe, tile, test); | 193 | ccs_test_run_tile(xe, tile, test); |
| 195 | } | 194 | } |
| 196 | 195 | ||
| 197 | xe_pm_runtime_put(xe); | ||
| 198 | |||
| 199 | return 0; | 196 | return 0; |
| 200 | } | 197 | } |
| 201 | 198 | ||
| @@ -356,13 +353,10 @@ static int evict_test_run_device(struct xe_device *xe) · 154 unmodified lines | |||
| 356 | return 0; | 353 | return 0; |
| 357 | } | 354 | } |
| 358 | 355 | ||
| 359 | xe_pm_runtime_get(xe); | 356 | guard(xe_pm_runtime)(xe); |
| 360 | |||
| 361 | for_each_tile(tile, xe, id) | 357 | for_each_tile(tile, xe, id) |
| 362 | evict_test_run_tile(xe, tile, test); | 358 | evict_test_run_tile(xe, tile, test); |
| 363 | 359 | ||
| 364 | xe_pm_runtime_put(xe); | ||
| 365 | |||
| 366 | return 0; | 360 | return 0; |
| 367 | } | 361 | } |
| 368 | 362 | ||
| @@ -266,7 +266,7 @@ static int dma_buf_run_device(struct xe_device *xe) · 265 unmodified lines | |||
| 266 | const struct dma_buf_test_params *params; | 266 | const struct dma_buf_test_params *params; |
| 267 | struct kunit *test = kunit_get_current_test(); | 267 | struct kunit *test = kunit_get_current_test(); |
| 268 | 268 | ||
| 269 | xe_pm_runtime_get(xe); | 269 | guard(xe_pm_runtime)(xe); |
| 270 | for (params = test_params; params->mem_mask; ++params) { | 270 | for (params = test_params; params->mem_mask; ++params) { |
| 271 | struct dma_buf_test_params p = *params; | 271 | struct dma_buf_test_params p = *params; |
| 272 | 272 | ||
| @@ -274,7 +274,6 @@ static int dma_buf_run_device(struct xe_device *xe) · 1 unmodified line | |||
| 274 | test->priv = &p; | 274 | test->priv = &p; |
| 275 | xe_test_dmabuf_import_same_driver(xe); | 275 | xe_test_dmabuf_import_same_driver(xe); |
| 276 | } | 276 | } |
| 277 | xe_pm_runtime_put(xe); | ||
| 278 | 277 | ||
| 279 | /* A non-zero return would halt iteration over driver devices */ | 278 | /* A non-zero return would halt iteration over driver devices */ |
| 280 | return 0; | 279 | return 0; |
| @@ -344,8 +344,7 @@ static int migrate_test_run_device(struct xe_device *xe) · 343 unmodified lines | |||
| 344 | struct xe_tile *tile; | 344 | struct xe_tile *tile; |
| 345 | int id; | 345 | int id; |
| 346 | 346 | ||
| 347 | xe_pm_runtime_get(xe); | 347 | guard(xe_pm_runtime)(xe); |
| 348 | |||
| 349 | for_each_tile(tile, xe, id) { | 348 | for_each_tile(tile, xe, id) { |
| 350 | struct xe_migrate *m = tile->migrate; | 349 | struct xe_migrate *m = tile->migrate; |
| 351 | struct drm_exec *exec = XE_VALIDATION_OPT_OUT; | 350 | struct drm_exec *exec = XE_VALIDATION_OPT_OUT; |
| @@ -356,8 +355,6 @@ static int migrate_test_run_device(struct xe_device *xe) · 4 unmodified lines | |||
| 356 | xe_vm_unlock(m->q->vm); | 355 | xe_vm_unlock(m->q->vm); |
| 357 | } | 356 | } |
| 358 | 357 | ||
| 359 | xe_pm_runtime_put(xe); | ||
| 360 | |||
| 361 | return 0; | 358 | return 0; |
| 362 | } | 359 | } |
| 363 | 360 | ||
| @@ -759,13 +756,10 @@ static int validate_ccs_test_run_device(struct xe_device *xe) · 395 unmodified lines | |||
| 759 | return 0; | 756 | return 0; |
| 760 | } | 757 | } |
| 761 | 758 | ||
| 762 | xe_pm_runtime_get(xe); | 759 | guard(xe_pm_runtime)(xe); |
| 763 | |||
| 764 | for_each_tile(tile, xe, id) | 760 | for_each_tile(tile, xe, id) |
| 765 | validate_ccs_test_run_tile(xe, tile, test); | 761 | validate_ccs_test_run_tile(xe, tile, test); |
| 766 | 762 | ||
| 767 | xe_pm_runtime_put(xe); | ||
| 768 | |||
| 769 | return 0; | 763 | return 0; |
| 770 | } | 764 | } |
| 771 | 765 | ||
| @@ -43,14 +43,12 @@ static void read_l3cc_table(struct xe_gt *gt, · 42 unmodified lines | |||
| 43 | { | 43 | { |
| 44 | struct kunit *test = kunit_get_current_test(); | 44 | struct kunit *test = kunit_get_current_test(); |
| 45 | u32 l3cc, l3cc_expected; | 45 | u32 l3cc, l3cc_expected; |
| 46 | unsigned int fw_ref, i; | 46 | unsigned int i; |
| 47 | u32 reg_val; | 47 | u32 reg_val; |
| 48 | 48 | ||
| 49 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | 49 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 50 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { | 50 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) |
| 51 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 52 | KUNIT_FAIL_AND_ABORT(test, "Forcewake Failed.\n"); | 51 | KUNIT_FAIL_AND_ABORT(test, "Forcewake Failed.\n"); |
| 53 | } | ||
| 54 | 52 | ||
| 55 | for (i = 0; i < info->num_mocs_regs; i++) { | 53 | for (i = 0; i < info->num_mocs_regs; i++) { |
| 56 | if (!(i & 1)) { | 54 | if (!(i & 1)) { |
| @@ -74,7 +72,6 @@ static void read_l3cc_table(struct xe_gt *gt, · 17 unmodified lines | |||
| 74 | KUNIT_EXPECT_EQ_MSG(test, l3cc_expected, l3cc, | 72 | KUNIT_EXPECT_EQ_MSG(test, l3cc_expected, l3cc, |
| 75 | "l3cc idx=%u has incorrect val.\n", i); | 73 | "l3cc idx=%u has incorrect val.\n", i); |
| 76 | } | 74 | } |
| 77 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 78 | } | 75 | } |
| 79 | 76 | ||
| 80 | static void read_mocs_table(struct xe_gt *gt, | 77 | static void read_mocs_table(struct xe_gt *gt, |
| @@ -82,14 +79,14 @@ static void read_mocs_table(struct xe_gt *gt, · 1 unmodified line | |||
| 82 | { | 79 | { |
| 83 | struct kunit *test = kunit_get_current_test(); | 80 | struct kunit *test = kunit_get_current_test(); |
| 84 | u32 mocs, mocs_expected; | 81 | u32 mocs, mocs_expected; |
| 85 | unsigned int fw_ref, i; | 82 | unsigned int i; |
| 86 | u32 reg_val; | 83 | u32 reg_val; |
| 87 | 84 | ||
| 88 | KUNIT_EXPECT_TRUE_MSG(test, info->unused_entries_index, | 85 | KUNIT_EXPECT_TRUE_MSG(test, info->unused_entries_index, |
| 89 | "Unused entries index should have been defined\n"); | 86 | "Unused entries index should have been defined\n"); |
| 90 | 87 | ||
| 91 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 88 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 92 | KUNIT_ASSERT_NE_MSG(test, fw_ref, 0, "Forcewake Failed.\n"); | 89 | KUNIT_ASSERT_NE_MSG(test, fw_ref.domains, 0, "Forcewake Failed.\n"); |
| 93 | 90 | ||
| 94 | for (i = 0; i < info->num_mocs_regs; i++) { | 91 | for (i = 0; i < info->num_mocs_regs; i++) { |
| 95 | if (regs_are_mcr(gt)) | 92 | if (regs_are_mcr(gt)) |
| @@ -106,8 +103,6 @@ static void read_mocs_table(struct xe_gt *gt, · 10 unmodified lines | |||
| 106 | KUNIT_EXPECT_EQ_MSG(test, mocs_expected, mocs, | 103 | KUNIT_EXPECT_EQ_MSG(test, mocs_expected, mocs, |
| 107 | "mocs reg 0x%x has incorrect val.\n", i); | 104 | "mocs reg 0x%x has incorrect val.\n", i); |
| 108 | } | 105 | } |
| 109 | |||
| 110 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 111 | } | 106 | } |
| 112 | 107 | ||
| 113 | static int mocs_kernel_test_run_device(struct xe_device *xe) | 108 | static int mocs_kernel_test_run_device(struct xe_device *xe) |
| @@ -120,8 +115,7 @@ static int mocs_kernel_test_run_device(struct xe_device *xe) · 6 unmodified lines | |||
| 120 | unsigned int flags; | 115 | unsigned int flags; |
| 121 | int id; | 116 | int id; |
| 122 | 117 | ||
| 123 | xe_pm_runtime_get(xe); | 118 | guard(xe_pm_runtime)(xe); |
| 124 | |||
| 125 | for_each_gt(gt, xe, id) { | 119 | for_each_gt(gt, xe, id) { |
| 126 | flags = live_mocs_init(&mocs, gt); | 120 | flags = live_mocs_init(&mocs, gt); |
| 127 | if (flags & HAS_GLOBAL_MOCS) | 121 | if (flags & HAS_GLOBAL_MOCS) |
| @@ -130,8 +124,6 @@ static int mocs_kernel_test_run_device(struct xe_device *xe) · 2 unmodified lines | |||
| 130 | read_l3cc_table(gt, &mocs.table); | 124 | read_l3cc_table(gt, &mocs.table); |
| 131 | } | 125 | } |
| 132 | 126 | ||
| 133 | xe_pm_runtime_put(xe); | ||
| 134 | |||
| 135 | return 0; | 127 | return 0; |
| 136 | } | 128 | } |
| 137 | 129 | ||
| @@ -155,8 +147,7 @@ static int mocs_reset_test_run_device(struct xe_device *xe) · 17 unmodified lines | |||
| 155 | int id; | 147 | int id; |
| 156 | struct kunit *test = kunit_get_current_test(); | 148 | struct kunit *test = kunit_get_current_test(); |
| 157 | 149 | ||
| 158 | xe_pm_runtime_get(xe); | 150 | guard(xe_pm_runtime)(xe); |
| 159 | |||
| 160 | for_each_gt(gt, xe, id) { | 151 | for_each_gt(gt, xe, id) { |
| 161 | flags = live_mocs_init(&mocs, gt); | 152 | flags = live_mocs_init(&mocs, gt); |
| 162 | kunit_info(test, "mocs_reset_test before reset\n"); | 153 | kunit_info(test, "mocs_reset_test before reset\n"); |
| @@ -174,8 +165,6 @@ static int mocs_reset_test_run_device(struct xe_device *xe) · 11 unmodified lines | |||
| 174 | read_l3cc_table(gt, &mocs.table); | 165 | read_l3cc_table(gt, &mocs.table); |
| 175 | } | 166 | } |
| 176 | 167 | ||
| 177 | xe_pm_runtime_put(xe); | ||
| 178 | |||
| 179 | return 0; | 168 | return 0; |
| 180 | } | 169 | } |
| 181 | 170 | ||
| @@ -121,6 +121,33 @@ · 120 unmodified lines | |||
| 121 | #define PICK_ARG11(args...) PICK_ARG10(DROP_FIRST_ARG(args)) | 121 | #define PICK_ARG11(args...) PICK_ARG10(DROP_FIRST_ARG(args)) |
| 122 | #define PICK_ARG12(args...) PICK_ARG11(DROP_FIRST_ARG(args)) | 122 | #define PICK_ARG12(args...) PICK_ARG11(DROP_FIRST_ARG(args)) |
| 123 | 123 | ||
| 124 | /** | ||
| 125 | * IF_ARGS() - Make selection based on optional argument list. | ||
| 126 | * @then: token to return if arguments are present | ||
| 127 | * @else: token to return if arguments are empty | ||
| 128 | * @...: arguments to check (optional) | ||
| 129 | * | ||
| 130 | * This macro allows to select a token based on the presence of the argument list. | ||
| 131 | * | ||
| 132 | * Example: | ||
| 133 | * | ||
| 134 | * #define foo X, Y | ||
| 135 | * #define bar IF_ARGS(Z, Q, foo) | ||
| 136 | * #define buz IF_ARGS(Z, Q, DROP_FIRST_ARG(FIRST_ARG(foo))) | ||
| 137 | * | ||
| 138 | * With above definitions bar expands to Z while buz expands to Q. | ||
| 139 | */ | ||
| 140 | #if defined(CONFIG_CC_IS_CLANG) || GCC_VERSION >= 100100 | ||
| 141 | #define IF_ARGS(then, else, ...) FIRST_ARG(__VA_OPT__(then,) else) | ||
| 142 | #else | ||
| 143 | #define IF_ARGS(then, else, ...) _IF_ARGS(then, else, CALL_ARGS(FIRST_ARG, __VA_ARGS__)) | ||
| 144 | #define _IF_ARGS(then, else, ...) __IF_ARGS(then, else, CALL_ARGS(COUNT_ARGS, __VA_ARGS__)) | ||
| 145 | #define __IF_ARGS(then, else, n) ___IF_ARGS(then, else, CALL_ARGS(CONCATENATE, ___IF_ARG, n)) | ||
| 146 | #define ___IF_ARGS(then, else, if) CALL_ARGS(if, then, else) | ||
| 147 | #define ___IF_ARG1(then, else) then | ||
| 148 | #define ___IF_ARG0(then, else) else | ||
| 149 | #endif | ||
| 150 | |||
| 124 | /** | 151 | /** |
| 125 | * ARGS_SEP_COMMA - Definition of a comma character. | 152 | * ARGS_SEP_COMMA - Definition of a comma character. |
| 126 | * | 153 | * |
| @@ -516,8 +516,7 @@ static struct ttm_tt *xe_ttm_tt_create(struct ttm_buffer_object *ttm_bo, · 515 unmodified lines | |||
| 516 | * non-coherent and require a CPU:WC mapping. | 516 | * non-coherent and require a CPU:WC mapping. |
| 517 | */ | 517 | */ |
| 518 | if ((!bo->cpu_caching && bo->flags & XE_BO_FLAG_SCANOUT) || | 518 | if ((!bo->cpu_caching && bo->flags & XE_BO_FLAG_SCANOUT) || |
| 519 | (xe->info.graphics_verx100 >= 1270 && | 519 | (!xe->info.has_cached_pt && bo->flags & XE_BO_FLAG_PAGETABLE)) |
| 520 | bo->flags & XE_BO_FLAG_PAGETABLE)) | ||
| 521 | caching = ttm_write_combined; | 520 | caching = ttm_write_combined; |
| 522 | } | 521 | } |
| 523 | 522 | ||
| @@ -2026,13 +2025,9 @@ static int xe_bo_vm_access(struct vm_area_struct *vma, unsigned long addr, · 1502 unmodified lines | |||
| 2026 | struct ttm_buffer_object *ttm_bo = vma->vm_private_data; | 2025 | struct ttm_buffer_object *ttm_bo = vma->vm_private_data; |
| 2027 | struct xe_bo *bo = ttm_to_xe_bo(ttm_bo); | 2026 | struct xe_bo *bo = ttm_to_xe_bo(ttm_bo); |
| 2028 | struct xe_device *xe = xe_bo_device(bo); | 2027 | struct xe_device *xe = xe_bo_device(bo); |
| 2029 | int ret; | ||
| 2030 | |||
| 2031 | xe_pm_runtime_get(xe); | ||
| 2032 | ret = ttm_bo_vm_access(vma, addr, buf, len, write); | ||
| 2033 | xe_pm_runtime_put(xe); | ||
| 2034 | 2028 | ||
| 2035 | return ret; | 2029 | guard(xe_pm_runtime)(xe); |
| 2030 | return ttm_bo_vm_access(vma, addr, buf, len, write); | ||
| 2036 | } | 2031 | } |
| 2037 | 2032 | ||
| 2038 | /** | 2033 | /** |
| @@ -3176,7 +3171,8 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data, · 1137 unmodified lines | |||
| 3176 | if (XE_IOCTL_DBG(xe, args->flags & | 3171 | if (XE_IOCTL_DBG(xe, args->flags & |
| 3177 | ~(DRM_XE_GEM_CREATE_FLAG_DEFER_BACKING | | 3172 | ~(DRM_XE_GEM_CREATE_FLAG_DEFER_BACKING | |
| 3178 | DRM_XE_GEM_CREATE_FLAG_SCANOUT | | 3173 | DRM_XE_GEM_CREATE_FLAG_SCANOUT | |
| 3179 | DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM))) | 3174 | DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM | |
| 3175 | DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION))) | ||
| 3180 | return -EINVAL; | 3176 | return -EINVAL; |
| 3181 | 3177 | ||
| 3182 | if (XE_IOCTL_DBG(xe, args->handle)) | 3178 | if (XE_IOCTL_DBG(xe, args->handle)) |
| @@ -3198,6 +3194,12 @@ int xe_gem_create_ioctl(struct drm_device *dev, void *data, · 15 unmodified lines | |||
| 3198 | if (args->flags & DRM_XE_GEM_CREATE_FLAG_SCANOUT) | 3194 | if (args->flags & DRM_XE_GEM_CREATE_FLAG_SCANOUT) |
| 3199 | bo_flags |= XE_BO_FLAG_SCANOUT; | 3195 | bo_flags |= XE_BO_FLAG_SCANOUT; |
| 3200 | 3196 | ||
| 3197 | if (args->flags & DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION) { | ||
| 3198 | if (XE_IOCTL_DBG(xe, GRAPHICS_VER(xe) < 20)) | ||
| 3199 | return -EOPNOTSUPP; | ||
| 3200 | bo_flags |= XE_BO_FLAG_NO_COMPRESSION; | ||
| 3201 | } | ||
| 3202 | |||
| 3201 | bo_flags |= args->placement << (ffs(XE_BO_FLAG_SYSTEM) - 1); | 3203 | bo_flags |= args->placement << (ffs(XE_BO_FLAG_SYSTEM) - 1); |
| 3202 | 3204 | ||
| 3203 | /* CCS formats need physical placement at a 64K alignment in VRAM. */ | 3205 | /* CCS formats need physical placement at a 64K alignment in VRAM. */ |
| @@ -3519,8 +3521,12 @@ bool xe_bo_needs_ccs_pages(struct xe_bo *bo) · 315 unmodified lines | |||
| 3519 | * Compression implies coh_none, therefore we know for sure that WB | 3521 | * Compression implies coh_none, therefore we know for sure that WB |
| 3520 | * memory can't currently use compression, which is likely one of the | 3522 | * memory can't currently use compression, which is likely one of the |
| 3521 | * common cases. | 3523 | * common cases. |
| 3524 | * Additionally, userspace may explicitly request no compression via the | ||
| 3525 | * DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION flag, which should also disable | ||
| 3526 | * CCS usage. | ||
| 3522 | */ | 3527 | */ |
| 3523 | if (bo->cpu_caching == DRM_XE_GEM_CPU_CACHING_WB) | 3528 | if (bo->cpu_caching == DRM_XE_GEM_CPU_CACHING_WB || |
| 3529 | bo->flags & XE_BO_FLAG_NO_COMPRESSION) | ||
| 3524 | return false; | 3530 | return false; |
| 3525 | 3531 | ||
| 3526 | return true; | 3532 | return true; |
| @@ -50,6 +50,7 @@ · 49 unmodified lines | |||
| 50 | #define XE_BO_FLAG_GGTT3 BIT(23) | 50 | #define XE_BO_FLAG_GGTT3 BIT(23) |
| 51 | #define XE_BO_FLAG_CPU_ADDR_MIRROR BIT(24) | 51 | #define XE_BO_FLAG_CPU_ADDR_MIRROR BIT(24) |
| 52 | #define XE_BO_FLAG_FORCE_USER_VRAM BIT(25) | 52 | #define XE_BO_FLAG_FORCE_USER_VRAM BIT(25) |
| 53 | #define XE_BO_FLAG_NO_COMPRESSION BIT(26) | ||
| 53 | 54 | ||
| 54 | /* this one is trigger internally only */ | 55 | /* this one is trigger internally only */ |
| 55 | #define XE_BO_FLAG_INTERNAL_TEST BIT(30) | 56 | #define XE_BO_FLAG_INTERNAL_TEST BIT(30) |
| @@ -68,7 +68,7 @@ static int info(struct seq_file *m, void *data) · 67 unmodified lines | |||
| 68 | struct xe_gt *gt; | 68 | struct xe_gt *gt; |
| 69 | u8 id; | 69 | u8 id; |
| 70 | 70 | ||
| 71 | xe_pm_runtime_get(xe); | 71 | guard(xe_pm_runtime)(xe); |
| 72 | 72 | ||
| 73 | drm_printf(&p, "graphics_verx100 %d\n", xe->info.graphics_verx100); | 73 | drm_printf(&p, "graphics_verx100 %d\n", xe->info.graphics_verx100); |
| 74 | drm_printf(&p, "media_verx100 %d\n", xe->info.media_verx100); | 74 | drm_printf(&p, "media_verx100 %d\n", xe->info.media_verx100); |
| @@ -93,9 +93,10 @@ static int info(struct seq_file *m, void *data) · 18 unmodified lines | |||
| 93 | xe_force_wake_ref(gt_to_fw(gt), XE_FW_GT)); | 93 | xe_force_wake_ref(gt_to_fw(gt), XE_FW_GT)); |
| 94 | drm_printf(&p, "gt%d engine_mask 0x%llx\n", id, | 94 | drm_printf(&p, "gt%d engine_mask 0x%llx\n", id, |
| 95 | gt->info.engine_mask); | 95 | gt->info.engine_mask); |
| 96 | drm_printf(&p, "gt%d multi_queue_engine_class_mask 0x%x\n", id, | ||
| 97 | gt->info.multi_queue_engine_class_mask); | ||
| 96 | } | 98 | } |
| 97 | 99 | ||
| 98 | xe_pm_runtime_put(xe); | ||
| 99 | return 0; | 100 | return 0; |
| 100 | } | 101 | } |
| 101 | 102 | ||
| @@ -110,9 +111,8 @@ static int sriov_info(struct seq_file *m, void *data) · 8 unmodified lines | |||
| 110 | 111 | ||
| 111 | static int workarounds(struct xe_device *xe, struct drm_printer *p) | 112 | static int workarounds(struct xe_device *xe, struct drm_printer *p) |
| 112 | { | 113 | { |
| 113 | xe_pm_runtime_get(xe); | 114 | guard(xe_pm_runtime)(xe); |
| 114 | xe_wa_device_dump(xe, p); | 115 | xe_wa_device_dump(xe, p); |
| 115 | xe_pm_runtime_put(xe); | ||
| 116 | 116 | ||
| 117 | return 0; | 117 | return 0; |
| 118 | } | 118 | } |
| @@ -134,7 +134,7 @@ static int dgfx_pkg_residencies_show(struct seq_file *m, void *data) · 15 unmodified lines | |||
| 134 | 134 | ||
| 135 | xe = node_to_xe(m->private); | 135 | xe = node_to_xe(m->private); |
| 136 | p = drm_seq_file_printer(m); | 136 | p = drm_seq_file_printer(m); |
| 137 | xe_pm_runtime_get(xe); | 137 | guard(xe_pm_runtime)(xe); |
| 138 | mmio = xe_root_tile_mmio(xe); | 138 | mmio = xe_root_tile_mmio(xe); |
| 139 | static const struct { | 139 | static const struct { |
| 140 | u32 offset; | 140 | u32 offset; |
| @@ -151,7 +151,6 @@ static int dgfx_pkg_residencies_show(struct seq_file *m, void *data) · 10 unmodified lines | |||
| 151 | for (int i = 0; i < ARRAY_SIZE(residencies); i++) | 151 | for (int i = 0; i < ARRAY_SIZE(residencies); i++) |
| 152 | read_residency_counter(xe, mmio, residencies[i].offset, residencies[i].name, &p); | 152 | read_residency_counter(xe, mmio, residencies[i].offset, residencies[i].name, &p); |
| 153 | 153 | ||
| 154 | xe_pm_runtime_put(xe); | ||
| 155 | return 0; | 154 | return 0; |
| 156 | } | 155 | } |
| 157 | 156 | ||
| @@ -163,7 +162,7 @@ static int dgfx_pcie_link_residencies_show(struct seq_file *m, void *data) · 5 unmodified lines | |||
| 163 | 162 | ||
| 164 | xe = node_to_xe(m->private); | 163 | xe = node_to_xe(m->private); |
| 165 | p = drm_seq_file_printer(m); | 164 | p = drm_seq_file_printer(m); |
| 166 | xe_pm_runtime_get(xe); | 165 | guard(xe_pm_runtime)(xe); |
| 167 | mmio = xe_root_tile_mmio(xe); | 166 | mmio = xe_root_tile_mmio(xe); |
| 168 | 167 | ||
| 169 | static const struct { | 168 | static const struct { |
| @@ -178,7 +177,6 @@ static int dgfx_pcie_link_residencies_show(struct seq_file *m, void *data) · 8 unmodified lines | |||
| 178 | for (int i = 0; i < ARRAY_SIZE(residencies); i++) | 177 | for (int i = 0; i < ARRAY_SIZE(residencies); i++) |
| 179 | read_residency_counter(xe, mmio, residencies[i].offset, residencies[i].name, &p); | 178 | read_residency_counter(xe, mmio, residencies[i].offset, residencies[i].name, &p); |
| 180 | 179 | ||
| 181 | xe_pm_runtime_put(xe); | ||
| 182 | return 0; | 180 | return 0; |
| 183 | } | 181 | } |
| 184 | 182 | ||
| @@ -277,16 +275,14 @@ static ssize_t wedged_mode_set(struct file *f, const char __user *ubuf, · 92 unmodified lines | |||
| 277 | 275 | ||
| 278 | xe->wedged.mode = wedged_mode; | 276 | xe->wedged.mode = wedged_mode; |
| 279 | 277 | ||
| 280 | xe_pm_runtime_get(xe); | 278 | guard(xe_pm_runtime)(xe); |
| 281 | for_each_gt(gt, xe, id) { | 279 | for_each_gt(gt, xe, id) { |
| 282 | ret = xe_guc_ads_scheduler_policy_toggle_reset(>->uc.guc.ads); | 280 | ret = xe_guc_ads_scheduler_policy_toggle_reset(>->uc.guc.ads); |
| 283 | if (ret) { | 281 | if (ret) { |
| 284 | xe_gt_err(gt, "Failed to update GuC ADS scheduler policy. GuC may still cause engine reset even with wedged_mode=2\n"); | 282 | xe_gt_err(gt, "Failed to update GuC ADS scheduler policy. GuC may still cause engine reset even with wedged_mode=2\n"); |
| 285 | xe_pm_runtime_put(xe); | ||
| 286 | return -EIO; | 283 | return -EIO; |
| 287 | } | 284 | } |
| 288 | } | 285 | } |
| 289 | xe_pm_runtime_put(xe); | ||
| 290 | 286 | ||
| 291 | return size; | 287 | return size; |
| 292 | } | 288 | } |
| @@ -297,6 +293,39 @@ static const struct file_operations wedged_mode_fops = { · 4 unmodified lines | |||
| 297 | .write = wedged_mode_set, | 293 | .write = wedged_mode_set, |
| 298 | }; | 294 | }; |
| 299 | 295 | ||
| 296 | static ssize_t page_reclaim_hw_assist_show(struct file *f, char __user *ubuf, | ||
| 297 | size_t size, loff_t *pos) | ||
| 298 | { | ||
| 299 | struct xe_device *xe = file_inode(f)->i_private; | ||
| 300 | char buf[8]; | ||
| 301 | int len; | ||
| 302 | |||
| 303 | len = scnprintf(buf, sizeof(buf), "%d\n", xe->info.has_page_reclaim_hw_assist); | ||
| 304 | return simple_read_from_buffer(ubuf, size, pos, buf, len); | ||
| 305 | } | ||
| 306 | |||
| 307 | static ssize_t page_reclaim_hw_assist_set(struct file *f, const char __user *ubuf, | ||
| 308 | size_t size, loff_t *pos) | ||
| 309 | { | ||
| 310 | struct xe_device *xe = file_inode(f)->i_private; | ||
| 311 | bool val; | ||
| 312 | ssize_t ret; | ||
| 313 | |||
| 314 | ret = kstrtobool_from_user(ubuf, size, &val); | ||
| 315 | if (ret) | ||
| 316 | return ret; | ||
| 317 | |||
| 318 | xe->info.has_page_reclaim_hw_assist = val; | ||
| 319 | |||
| 320 | return size; | ||
| 321 | } | ||
| 322 | |||
| 323 | static const struct file_operations page_reclaim_hw_assist_fops = { | ||
| 324 | .owner = THIS_MODULE, | ||
| 325 | .read = page_reclaim_hw_assist_show, | ||
| 326 | .write = page_reclaim_hw_assist_set, | ||
| 327 | }; | ||
| 328 | |||
| 300 | static ssize_t atomic_svm_timeslice_ms_show(struct file *f, char __user *ubuf, | 329 | static ssize_t atomic_svm_timeslice_ms_show(struct file *f, char __user *ubuf, |
| 301 | size_t size, loff_t *pos) | 330 | size_t size, loff_t *pos) |
| 302 | { | 331 | { |
| @@ -332,6 +361,74 @@ static const struct file_operations atomic_svm_timeslice_ms_fops = { · 29 unmodified lines | |||
| 332 | .write = atomic_svm_timeslice_ms_set, | 361 | .write = atomic_svm_timeslice_ms_set, |
| 333 | }; | 362 | }; |
| 334 | 363 | ||
| 364 | static ssize_t min_run_period_lr_ms_show(struct file *f, char __user *ubuf, | ||
| 365 | size_t size, loff_t *pos) | ||
| 366 | { | ||
| 367 | struct xe_device *xe = file_inode(f)->i_private; | ||
| 368 | char buf[32]; | ||
| 369 | int len = 0; | ||
| 370 | |||
| 371 | len = scnprintf(buf, sizeof(buf), "%d\n", xe->min_run_period_lr_ms); | ||
| 372 | |||
| 373 | return simple_read_from_buffer(ubuf, size, pos, buf, len); | ||
| 374 | } | ||
| 375 | |||
| 376 | static ssize_t min_run_period_lr_ms_set(struct file *f, const char __user *ubuf, | ||
| 377 | size_t size, loff_t *pos) | ||
| 378 | { | ||
| 379 | struct xe_device *xe = file_inode(f)->i_private; | ||
| 380 | u32 min_run_period_lr_ms; | ||
| 381 | ssize_t ret; | ||
| 382 | |||
| 383 | ret = kstrtouint_from_user(ubuf, size, 0, &min_run_period_lr_ms); | ||
| 384 | if (ret) | ||
| 385 | return ret; | ||
| 386 | |||
| 387 | xe->min_run_period_lr_ms = min_run_period_lr_ms; | ||
| 388 | |||
| 389 | return size; | ||
| 390 | } | ||
| 391 | |||
| 392 | static const struct file_operations min_run_period_lr_ms_fops = { | ||
| 393 | .owner = THIS_MODULE, | ||
| 394 | .read = min_run_period_lr_ms_show, | ||
| 395 | .write = min_run_period_lr_ms_set, | ||
| 396 | }; | ||
| 397 | |||
| 398 | static ssize_t min_run_period_pf_ms_show(struct file *f, char __user *ubuf, | ||
| 399 | size_t size, loff_t *pos) | ||
| 400 | { | ||
| 401 | struct xe_device *xe = file_inode(f)->i_private; | ||
| 402 | char buf[32]; | ||
| 403 | int len = 0; | ||
| 404 | |||
| 405 | len = scnprintf(buf, sizeof(buf), "%d\n", xe->min_run_period_pf_ms); | ||
| 406 | |||
| 407 | return simple_read_from_buffer(ubuf, size, pos, buf, len); | ||
| 408 | } | ||
| 409 | |||
| 410 | static ssize_t min_run_period_pf_ms_set(struct file *f, const char __user *ubuf, | ||
| 411 | size_t size, loff_t *pos) | ||
| 412 | { | ||
| 413 | struct xe_device *xe = file_inode(f)->i_private; | ||
| 414 | u32 min_run_period_pf_ms; | ||
| 415 | ssize_t ret; | ||
| 416 | |||
| 417 | ret = kstrtouint_from_user(ubuf, size, 0, &min_run_period_pf_ms); | ||
| 418 | if (ret) | ||
| 419 | return ret; | ||
| 420 | |||
| 421 | xe->min_run_period_pf_ms = min_run_period_pf_ms; | ||
| 422 | |||
| 423 | return size; | ||
| 424 | } | ||
| 425 | |||
| 426 | static const struct file_operations min_run_period_pf_ms_fops = { | ||
| 427 | .owner = THIS_MODULE, | ||
| 428 | .read = min_run_period_pf_ms_show, | ||
| 429 | .write = min_run_period_pf_ms_set, | ||
| 430 | }; | ||
| 431 | |||
| 335 | static ssize_t disable_late_binding_show(struct file *f, char __user *ubuf, | 432 | static ssize_t disable_late_binding_show(struct file *f, char __user *ubuf, |
| 336 | size_t size, loff_t *pos) | 433 | size_t size, loff_t *pos) |
| 337 | { | 434 | { |
| @@ -375,7 +472,6 @@ void xe_debugfs_register(struct xe_device *xe) · 37 unmodified lines | |||
| 375 | struct ttm_resource_manager *man; | 472 | struct ttm_resource_manager *man; |
| 376 | struct xe_tile *tile; | 473 | struct xe_tile *tile; |
| 377 | struct xe_gt *gt; | 474 | struct xe_gt *gt; |
| 378 | u32 mem_type; | ||
| 379 | u8 tile_id; | 475 | u8 tile_id; |
| 380 | u8 id; | 476 | u8 id; |
| 381 | 477 | ||
| @@ -400,19 +496,22 @@ void xe_debugfs_register(struct xe_device *xe) · 18 unmodified lines | |||
| 400 | debugfs_create_file("atomic_svm_timeslice_ms", 0600, root, xe, | 496 | debugfs_create_file("atomic_svm_timeslice_ms", 0600, root, xe, |
| 401 | &atomic_svm_timeslice_ms_fops); | 497 | &atomic_svm_timeslice_ms_fops); |
| 402 | 498 | ||
| 403 | debugfs_create_file("disable_late_binding", 0600, root, xe, | 499 | debugfs_create_file("min_run_period_lr_ms", 0600, root, xe, |
| 404 | &disable_late_binding_fops); | 500 | &min_run_period_lr_ms_fops); |
| 405 | 501 | ||
| 406 | for (mem_type = XE_PL_VRAM0; mem_type <= XE_PL_VRAM1; ++mem_type) { | 502 | debugfs_create_file("min_run_period_pf_ms", 0600, root, xe, |
| 407 | man = ttm_manager_type(bdev, mem_type); | 503 | &min_run_period_pf_ms_fops); |
| 408 | 504 | ||
| 409 | if (man) { | 505 | debugfs_create_file("disable_late_binding", 0600, root, xe, |
| 410 | char name[16]; | 506 | &disable_late_binding_fops); |
| 411 | 507 | ||
| 412 | snprintf(name, sizeof(name), "vram%d_mm", mem_type - XE_PL_VRAM0); | 508 | /* |
| 413 | ttm_resource_manager_create_debugfs(man, root, name); | 509 | * Don't expose page reclaim configuration file if not supported by the |
| 414 | } | 510 | * hardware initially. |
| 415 | } | 511 | */ |
| 512 | if (xe->info.has_page_reclaim_hw_assist) | ||
| 513 | debugfs_create_file("page_reclaim_hw_assist", 0600, root, xe, | ||
| 514 | &page_reclaim_hw_assist_fops); | ||
| 416 | 515 | ||
| 417 | man = ttm_manager_type(bdev, XE_PL_TT); | 516 | man = ttm_manager_type(bdev, XE_PL_TT); |
| 418 | ttm_resource_manager_create_debugfs(man, root, "gtt_mm"); | 517 | ttm_resource_manager_create_debugfs(man, root, "gtt_mm"); |
| @@ -276,7 +276,6 @@ static void xe_devcoredump_deferred_snap_work(struct work_struct *work) · 275 unmodified lines | |||
| 276 | struct xe_devcoredump_snapshot *ss = container_of(work, typeof(*ss), work); | 276 | struct xe_devcoredump_snapshot *ss = container_of(work, typeof(*ss), work); |
| 277 | struct xe_devcoredump *coredump = container_of(ss, typeof(*coredump), snapshot); | 277 | struct xe_devcoredump *coredump = container_of(ss, typeof(*coredump), snapshot); |
| 278 | struct xe_device *xe = coredump_to_xe(coredump); | 278 | struct xe_device *xe = coredump_to_xe(coredump); |
| 279 | unsigned int fw_ref; | ||
| 280 | 279 | ||
| 281 | /* | 280 | /* |
| 282 | * NB: Despite passing a GFP_ flags parameter here, more allocations are done | 281 | * NB: Despite passing a GFP_ flags parameter here, more allocations are done |
| @@ -287,15 +286,15 @@ static void xe_devcoredump_deferred_snap_work(struct work_struct *work) · 4 unmodified lines | |||
| 287 | xe_devcoredump_read, xe_devcoredump_free, | 286 | xe_devcoredump_read, xe_devcoredump_free, |
| 288 | XE_COREDUMP_TIMEOUT_JIFFIES); | 287 | XE_COREDUMP_TIMEOUT_JIFFIES); |
| 289 | 288 | ||
| 290 | xe_pm_runtime_get(xe); | 289 | guard(xe_pm_runtime)(xe); |
| 291 | 290 | ||
| 292 | /* keep going if fw fails as we still want to save the memory and SW data */ | 291 | /* keep going if fw fails as we still want to save the memory and SW data */ |
| 293 | fw_ref = xe_force_wake_get(gt_to_fw(ss->gt), XE_FORCEWAKE_ALL); | 292 | xe_with_force_wake(fw_ref, gt_to_fw(ss->gt), XE_FORCEWAKE_ALL) { |
| 294 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) | 293 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) |
| 295 | xe_gt_info(ss->gt, "failed to get forcewake for coredump capture\n"); | 294 | xe_gt_info(ss->gt, "failed to get forcewake for coredump capture\n"); |
| 296 | xe_vm_snapshot_capture_delayed(ss->vm); | 295 | xe_vm_snapshot_capture_delayed(ss->vm); |
| 297 | xe_guc_exec_queue_snapshot_capture_delayed(ss->ge); | 296 | xe_guc_exec_queue_snapshot_capture_delayed(ss->ge); |
| 298 | xe_force_wake_put(gt_to_fw(ss->gt), fw_ref); | 297 | } |
| 299 | 298 | ||
| 300 | ss->read.chunk_position = 0; | 299 | ss->read.chunk_position = 0; |
| 301 | 300 | ||
| @@ -306,7 +305,7 @@ static void xe_devcoredump_deferred_snap_work(struct work_struct *work) · 4 unmodified lines | |||
| 306 | ss->read.buffer = kvmalloc(XE_DEVCOREDUMP_CHUNK_MAX, | 305 | ss->read.buffer = kvmalloc(XE_DEVCOREDUMP_CHUNK_MAX, |
| 307 | GFP_USER); | 306 | GFP_USER); |
| 308 | if (!ss->read.buffer) | 307 | if (!ss->read.buffer) |
| 309 | goto put_pm; | 308 | return; |
| 310 | 309 | ||
| 311 | __xe_devcoredump_read(ss->read.buffer, | 310 | __xe_devcoredump_read(ss->read.buffer, |
| 312 | XE_DEVCOREDUMP_CHUNK_MAX, | 311 | XE_DEVCOREDUMP_CHUNK_MAX, |
| @@ -314,15 +313,12 @@ static void xe_devcoredump_deferred_snap_work(struct work_struct *work) · 1 unmodified line | |||
| 314 | } else { | 313 | } else { |
| 315 | ss->read.buffer = kvmalloc(ss->read.size, GFP_USER); | 314 | ss->read.buffer = kvmalloc(ss->read.size, GFP_USER); |
| 316 | if (!ss->read.buffer) | 315 | if (!ss->read.buffer) |
| 317 | goto put_pm; | 316 | return; |
| 318 | 317 | ||
| 319 | __xe_devcoredump_read(ss->read.buffer, ss->read.size, 0, | 318 | __xe_devcoredump_read(ss->read.buffer, ss->read.size, 0, |
| 320 | coredump); | 319 | coredump); |
| 321 | xe_devcoredump_snapshot_free(ss); | 320 | xe_devcoredump_snapshot_free(ss); |
| 322 | } | 321 | } |
| 323 | |||
| 324 | put_pm: | ||
| 325 | xe_pm_runtime_put(xe); | ||
| 326 | } | 322 | } |
| 327 | 323 | ||
| 328 | static void devcoredump_snapshot(struct xe_devcoredump *coredump, | 324 | static void devcoredump_snapshot(struct xe_devcoredump *coredump, |
| @@ -332,7 +328,6 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump, · 3 unmodified lines | |||
| 332 | struct xe_devcoredump_snapshot *ss = &coredump->snapshot; | 328 | struct xe_devcoredump_snapshot *ss = &coredump->snapshot; |
| 333 | struct xe_guc *guc = exec_queue_to_guc(q); | 329 | struct xe_guc *guc = exec_queue_to_guc(q); |
| 334 | const char *process_name = "no process"; | 330 | const char *process_name = "no process"; |
| 335 | unsigned int fw_ref; | ||
| 336 | bool cookie; | 331 | bool cookie; |
| 337 | 332 | ||
| 338 | ss->snapshot_time = ktime_get_real(); | 333 | ss->snapshot_time = ktime_get_real(); |
| @@ -348,10 +343,10 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump, · 9 unmodified lines | |||
| 348 | ss->gt = q->gt; | 343 | ss->gt = q->gt; |
| 349 | INIT_WORK(&ss->work, xe_devcoredump_deferred_snap_work); | 344 | INIT_WORK(&ss->work, xe_devcoredump_deferred_snap_work); |
| 350 | 345 | ||
| 351 | cookie = dma_fence_begin_signalling(); | ||
| 352 | |||
| 353 | /* keep going if fw fails as we still want to save the memory and SW data */ | 346 | /* keep going if fw fails as we still want to save the memory and SW data */ |
| 354 | fw_ref = xe_force_wake_get(gt_to_fw(q->gt), XE_FORCEWAKE_ALL); | 347 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(q->gt), XE_FORCEWAKE_ALL); |
| 348 | |||
| 349 | cookie = dma_fence_begin_signalling(); | ||
| 355 | 350 | ||
| 356 | ss->guc.log = xe_guc_log_snapshot_capture(&guc->log, true); | 351 | ss->guc.log = xe_guc_log_snapshot_capture(&guc->log, true); |
| 357 | ss->guc.ct = xe_guc_ct_snapshot_capture(&guc->ct); | 352 | ss->guc.ct = xe_guc_ct_snapshot_capture(&guc->ct); |
| @@ -364,7 +359,6 @@ static void devcoredump_snapshot(struct xe_devcoredump *coredump, · 6 unmodified lines | |||
| 364 | 359 | ||
| 365 | queue_work(system_unbound_wq, &ss->work); | 360 | queue_work(system_unbound_wq, &ss->work); |
| 366 | 361 | ||
| 367 | xe_force_wake_put(gt_to_fw(q->gt), fw_ref); | ||
| 368 | dma_fence_end_signalling(cookie); | 362 | dma_fence_end_signalling(cookie); |
| 369 | } | 363 | } |
| 370 | 364 | ||
| @@ -166,7 +166,7 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file) · 165 unmodified lines | |||
| 166 | struct xe_exec_queue *q; | 166 | struct xe_exec_queue *q; |
| 167 | unsigned long idx; | 167 | unsigned long idx; |
| 168 | 168 | ||
| 169 | xe_pm_runtime_get(xe); | 169 | guard(xe_pm_runtime)(xe); |
| 170 | 170 | ||
| 171 | /* | 171 | /* |
| 172 | * No need for exec_queue.lock here as there is no contention for it | 172 | * No need for exec_queue.lock here as there is no contention for it |
| @@ -177,15 +177,18 @@ static void xe_file_close(struct drm_device *dev, struct drm_file *file) · 4 unmodified lines | |||
| 177 | xa_for_each(&xef->exec_queue.xa, idx, q) { | 177 | xa_for_each(&xef->exec_queue.xa, idx, q) { |
| 178 | if (q->vm && q->hwe->hw_engine_group) | 178 | if (q->vm && q->hwe->hw_engine_group) |
| 179 | xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); | 179 | xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); |
| 180 | xe_exec_queue_kill(q); | 180 | |
| 181 | if (xe_exec_queue_is_multi_queue_primary(q)) | ||
| 182 | xe_exec_queue_group_kill_put(q->multi_queue.group); | ||
| 183 | else | ||
| 184 | xe_exec_queue_kill(q); | ||
| 185 | |||
| 181 | xe_exec_queue_put(q); | 186 | xe_exec_queue_put(q); |
| 182 | } | 187 | } |
| 183 | xa_for_each(&xef->vm.xa, idx, vm) | 188 | xa_for_each(&xef->vm.xa, idx, vm) |
| 184 | xe_vm_close_and_put(vm); | 189 | xe_vm_close_and_put(vm); |
| 185 | 190 | ||
| 186 | xe_file_put(xef); | 191 | xe_file_put(xef); |
| 187 | |||
| 188 | xe_pm_runtime_put(xe); | ||
| 189 | } | 192 | } |
| 190 | 193 | ||
| 191 | static const struct drm_ioctl_desc xe_ioctls[] = { | 194 | static const struct drm_ioctl_desc xe_ioctls[] = { |
| @@ -209,6 +212,8 @@ static const struct drm_ioctl_desc xe_ioctls[] = { · 17 unmodified lines | |||
| 209 | DRM_IOCTL_DEF_DRV(XE_MADVISE, xe_vm_madvise_ioctl, DRM_RENDER_ALLOW), | 212 | DRM_IOCTL_DEF_DRV(XE_MADVISE, xe_vm_madvise_ioctl, DRM_RENDER_ALLOW), |
| 210 | DRM_IOCTL_DEF_DRV(XE_VM_QUERY_MEM_RANGE_ATTRS, xe_vm_query_vmas_attrs_ioctl, | 213 | DRM_IOCTL_DEF_DRV(XE_VM_QUERY_MEM_RANGE_ATTRS, xe_vm_query_vmas_attrs_ioctl, |
| 211 | DRM_RENDER_ALLOW), | 214 | DRM_RENDER_ALLOW), |
| 215 | DRM_IOCTL_DEF_DRV(XE_EXEC_QUEUE_SET_PROPERTY, xe_exec_queue_set_property_ioctl, | ||
| 216 | DRM_RENDER_ALLOW), | ||
| 212 | }; | 217 | }; |
| 213 | 218 | ||
| 214 | static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 219 | static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
| @@ -220,10 +225,10 @@ static long xe_drm_ioctl(struct file *file, unsigned int cmd, unsigned long arg) · 5 unmodified lines | |||
| 220 | if (xe_device_wedged(xe)) | 225 | if (xe_device_wedged(xe)) |
| 221 | return -ECANCELED; | 226 | return -ECANCELED; |
| 222 | 227 | ||
| 223 | ret = xe_pm_runtime_get_ioctl(xe); | 228 | ACQUIRE(xe_pm_runtime_ioctl, pm)(xe); |
| 229 | ret = ACQUIRE_ERR(xe_pm_runtime_ioctl, &pm); | ||
| 224 | if (ret >= 0) | 230 | if (ret >= 0) |
| 225 | ret = drm_ioctl(file, cmd, arg); | 231 | ret = drm_ioctl(file, cmd, arg); |
| 226 | xe_pm_runtime_put(xe); | ||
| 227 | 232 | ||
| 228 | return ret; | 233 | return ret; |
| 229 | } | 234 | } |
| @@ -238,10 +243,10 @@ static long xe_drm_compat_ioctl(struct file *file, unsigned int cmd, unsigned lo · 8 unmodified lines | |||
| 238 | if (xe_device_wedged(xe)) | 243 | if (xe_device_wedged(xe)) |
| 239 | return -ECANCELED; | 244 | return -ECANCELED; |
| 240 | 245 | ||
| 241 | ret = xe_pm_runtime_get_ioctl(xe); | 246 | ACQUIRE(xe_pm_runtime_ioctl, pm)(xe); |
| 247 | ret = ACQUIRE_ERR(xe_pm_runtime_ioctl, &pm); | ||
| 242 | if (ret >= 0) | 248 | if (ret >= 0) |
| 243 | ret = drm_compat_ioctl(file, cmd, arg); | 249 | ret = drm_compat_ioctl(file, cmd, arg); |
| 244 | xe_pm_runtime_put(xe); | ||
| 245 | 250 | ||
| 246 | return ret; | 251 | return ret; |
| 247 | } | 252 | } |
| @@ -455,6 +460,7 @@ struct xe_device *xe_device_create(struct pci_dev *pdev, · 207 unmodified lines | |||
| 455 | xe->info.revid = pdev->revision; | 460 | xe->info.revid = pdev->revision; |
| 456 | xe->info.force_execlist = xe_modparam.force_execlist; | 461 | xe->info.force_execlist = xe_modparam.force_execlist; |
| 457 | xe->atomic_svm_timeslice_ms = 5; | 462 | xe->atomic_svm_timeslice_ms = 5; |
| 463 | xe->min_run_period_lr_ms = 5; | ||
| 458 | 464 | ||
| 459 | err = xe_irq_init(xe); | 465 | err = xe_irq_init(xe); |
| 460 | if (err) | 466 | if (err) |
| @@ -775,7 +781,6 @@ ALLOW_ERROR_INJECTION(xe_device_probe_early, ERRNO); /* See xe_pci_probe() */ · 314 unmodified lines | |||
| 775 | static int probe_has_flat_ccs(struct xe_device *xe) | 781 | static int probe_has_flat_ccs(struct xe_device *xe) |
| 776 | { | 782 | { |
| 777 | struct xe_gt *gt; | 783 | struct xe_gt *gt; |
| 778 | unsigned int fw_ref; | ||
| 779 | u32 reg; | 784 | u32 reg; |
| 780 | 785 | ||
| 781 | /* Always enabled/disabled, no runtime check to do */ | 786 | /* Always enabled/disabled, no runtime check to do */ |
| @@ -786,8 +791,8 @@ static int probe_has_flat_ccs(struct xe_device *xe) · 4 unmodified lines | |||
| 786 | if (!gt) | 791 | if (!gt) |
| 787 | return 0; | 792 | return 0; |
| 788 | 793 | ||
| 789 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 794 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 790 | if (!fw_ref) | 795 | if (!fw_ref.domains) |
| 791 | return -ETIMEDOUT; | 796 | return -ETIMEDOUT; |
| 792 | 797 | ||
| 793 | reg = xe_gt_mcr_unicast_read_any(gt, XE2_FLAT_CCS_BASE_RANGE_LOWER); | 798 | reg = xe_gt_mcr_unicast_read_any(gt, XE2_FLAT_CCS_BASE_RANGE_LOWER); |
| @@ -797,11 +802,64 @@ static int probe_has_flat_ccs(struct xe_device *xe) · 3 unmodified lines | |||
| 797 | drm_dbg(&xe->drm, | 802 | drm_dbg(&xe->drm, |
| 798 | "Flat CCS has been disabled in bios, May lead to performance impact"); | 803 | "Flat CCS has been disabled in bios, May lead to performance impact"); |
| 799 | 804 | ||
| 800 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 801 | |||
| 802 | return 0; | 805 | return 0; |
| 803 | } | 806 | } |
| 804 | 807 | ||
| 808 | /* | ||
| 809 | * Detect if the driver is being run on pre-production hardware. We don't | ||
| 810 | * keep workarounds for pre-production hardware long term, so print an | ||
| 811 | * error and add taint if we're being loaded on a pre-production platform | ||
| 812 | * for which the pre-prod workarounds have already been removed. | ||
| 813 | * | ||
| 814 | * The general policy is that we'll remove any workarounds that only apply to | ||
| 815 | * pre-production hardware around the time force_probe restrictions are lifted | ||
| 816 | * for a platform of the next major IP generation (for example, Xe2 pre-prod | ||
| 817 | * workarounds should be removed around the time the first Xe3 platforms have | ||
| 818 | * force_probe lifted). | ||
| 819 | */ | ||
| 820 | static void detect_preproduction_hw(struct xe_device *xe) | ||
| 821 | { | ||
| 822 | struct xe_gt *gt; | ||
| 823 | int id; | ||
| 824 | |||
| 825 | /* | ||
| 826 | * SR-IOV VFs don't have access to the FUSE2 register, so we can't | ||
| 827 | * check pre-production status there. But the host OS will notice | ||
| 828 | * and report the pre-production status, which should be enough to | ||
| 829 | * help us catch mistaken use of pre-production hardware. | ||
| 830 | */ | ||
| 831 | if (IS_SRIOV_VF(xe)) | ||
| 832 | return; | ||
| 833 | |||
| 834 | /* | ||
| 835 | * The "SW_CAP" fuse contains a bit indicating whether the device is a | ||
| 836 | * production or pre-production device. This fuse is reflected through | ||
| 837 | * the GT "FUSE2" register, even though the contents of the fuse are | ||
| 838 | * not GT-specific. Every GT's reflection of this fuse should show the | ||
| 839 | * same value, so we'll just use the first available GT for lookup. | ||
| 840 | */ | ||
| 841 | for_each_gt(gt, xe, id) | ||
| 842 | break; | ||
| 843 | |||
| 844 | if (!gt) | ||
| 845 | return; | ||
| 846 | |||
| 847 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); | ||
| 848 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT)) { | ||
| 849 | xe_gt_err(gt, "Forcewake failure; cannot determine production/pre-production hw status.\n"); | ||
| 850 | return; | ||
| 851 | } | ||
| 852 | |||
| 853 | if (xe_mmio_read32(>->mmio, FUSE2) & PRODUCTION_HW) | ||
| 854 | return; | ||
| 855 | |||
| 856 | xe_info(xe, "Pre-production hardware detected.\n"); | ||
| 857 | if (!xe->info.has_pre_prod_wa) { | ||
| 858 | xe_err(xe, "Pre-production workarounds for this platform have already been removed.\n"); | ||
| 859 | add_taint(TAINT_MACHINE_CHECK, LOCKDEP_STILL_OK); | ||
| 860 | } | ||
| 861 | } | ||
| 862 | |||
| 805 | int xe_device_probe(struct xe_device *xe) | 863 | int xe_device_probe(struct xe_device *xe) |
| 806 | { | 864 | { |
| 807 | struct xe_tile *tile; | 865 | struct xe_tile *tile; |
| @@ -972,6 +1030,8 @@ int xe_device_probe(struct xe_device *xe) · 164 unmodified lines | |||
| 972 | if (err) | 1030 | if (err) |
| 973 | goto err_unregister_display; | 1031 | goto err_unregister_display; |
| 974 | 1032 | ||
| 1033 | detect_preproduction_hw(xe); | ||
| 1034 | |||
| 975 | return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe); | 1035 | return devm_add_action_or_reset(xe->drm.dev, xe_device_sanitize, xe); |
| 976 | 1036 | ||
| 977 | err_unregister_display: | 1037 | err_unregister_display: |
| @@ -1034,7 +1094,6 @@ void xe_device_wmb(struct xe_device *xe) · 56 unmodified lines | |||
| 1034 | */ | 1094 | */ |
| 1035 | static void tdf_request_sync(struct xe_device *xe) | 1095 | static void tdf_request_sync(struct xe_device *xe) |
| 1036 | { | 1096 | { |
| 1037 | unsigned int fw_ref; | ||
| 1038 | struct xe_gt *gt; | 1097 | struct xe_gt *gt; |
| 1039 | u8 id; | 1098 | u8 id; |
| 1040 | 1099 | ||
| @@ -1042,8 +1101,8 @@ static void tdf_request_sync(struct xe_device *xe) · 1 unmodified line | |||
| 1042 | if (xe_gt_is_media_type(gt)) | 1101 | if (xe_gt_is_media_type(gt)) |
| 1043 | continue; | 1102 | continue; |
| 1044 | 1103 | ||
| 1045 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 1104 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 1046 | if (!fw_ref) | 1105 | if (!fw_ref.domains) |
| 1047 | return; | 1106 | return; |
| 1048 | 1107 | ||
| 1049 | xe_mmio_write32(>->mmio, XE2_TDF_CTRL, TRANSIENT_FLUSH_REQUEST); | 1108 | xe_mmio_write32(>->mmio, XE2_TDF_CTRL, TRANSIENT_FLUSH_REQUEST); |
| @@ -1058,15 +1117,12 @@ static void tdf_request_sync(struct xe_device *xe) · 8 unmodified lines | |||
| 1058 | if (xe_mmio_wait32(>->mmio, XE2_TDF_CTRL, TRANSIENT_FLUSH_REQUEST, 0, | 1117 | if (xe_mmio_wait32(>->mmio, XE2_TDF_CTRL, TRANSIENT_FLUSH_REQUEST, 0, |
| 1059 | 300, NULL, false)) | 1118 | 300, NULL, false)) |
| 1060 | xe_gt_err_once(gt, "TD flush timeout\n"); | 1119 | xe_gt_err_once(gt, "TD flush timeout\n"); |
| 1061 | |||
| 1062 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 1063 | } | 1120 | } |
| 1064 | } | 1121 | } |
| 1065 | 1122 | ||
| 1066 | void xe_device_l2_flush(struct xe_device *xe) | 1123 | void xe_device_l2_flush(struct xe_device *xe) |
| 1067 | { | 1124 | { |
| 1068 | struct xe_gt *gt; | 1125 | struct xe_gt *gt; |
| 1069 | unsigned int fw_ref; | ||
| 1070 | 1126 | ||
| 1071 | gt = xe_root_mmio_gt(xe); | 1127 | gt = xe_root_mmio_gt(xe); |
| 1072 | if (!gt) | 1128 | if (!gt) |
| @@ -1075,8 +1131,8 @@ void xe_device_l2_flush(struct xe_device *xe) · 2 unmodified lines | |||
| 1075 | if (!XE_GT_WA(gt, 16023588340)) | 1131 | if (!XE_GT_WA(gt, 16023588340)) |
| 1076 | return; | 1132 | return; |
| 1077 | 1133 | ||
| 1078 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 1134 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 1079 | if (!fw_ref) | 1135 | if (!fw_ref.domains) |
| 1080 | return; | 1136 | return; |
| 1081 | 1137 | ||
| 1082 | spin_lock(>->global_invl_lock); | 1138 | spin_lock(>->global_invl_lock); |
| @@ -1086,8 +1142,6 @@ void xe_device_l2_flush(struct xe_device *xe) · 3 unmodified lines | |||
| 1086 | xe_gt_err_once(gt, "Global invalidation timeout\n"); | 1142 | xe_gt_err_once(gt, "Global invalidation timeout\n"); |
| 1087 | 1143 | ||
| 1088 | spin_unlock(>->global_invl_lock); | 1144 | spin_unlock(>->global_invl_lock); |
| 1089 | |||
| 1090 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 1091 | } | 1145 | } |
| 1092 | 1146 | ||
| 1093 | /** | 1147 | /** |
| @@ -172,6 +172,11 @@ static inline bool xe_device_has_lmtt(struct xe_device *xe) · 171 unmodified lines | |||
| 172 | return IS_DGFX(xe); | 172 | return IS_DGFX(xe); |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | static inline bool xe_device_has_mert(struct xe_device *xe) | ||
| 176 | { | ||
| 177 | return xe->info.has_mert; | ||
| 178 | } | ||
| 179 | |||
| 175 | u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size); | 180 | u32 xe_device_ccs_bytes(struct xe_device *xe, u64 size); |
| 176 | 181 | ||
| 177 | void xe_device_snapshot_print(struct xe_device *xe, struct drm_printer *p); | 182 | void xe_device_snapshot_print(struct xe_device *xe, struct drm_printer *p); |
| @@ -57,9 +57,8 @@ vram_d3cold_threshold_store(struct device *dev, struct device_attribute *attr, · 56 unmodified lines | |||
| 57 | 57 | ||
| 58 | drm_dbg(&xe->drm, "vram_d3cold_threshold: %u\n", vram_d3cold_threshold); | 58 | drm_dbg(&xe->drm, "vram_d3cold_threshold: %u\n", vram_d3cold_threshold); |
| 59 | 59 | ||
| 60 | xe_pm_runtime_get(xe); | 60 | guard(xe_pm_runtime)(xe); |
| 61 | ret = xe_pm_set_vram_threshold(xe, vram_d3cold_threshold); | 61 | ret = xe_pm_set_vram_threshold(xe, vram_d3cold_threshold); |
| 62 | xe_pm_runtime_put(xe); | ||
| 63 | 62 | ||
| 64 | return ret ?: count; | 63 | return ret ?: count; |
| 65 | } | 64 | } |
| @@ -84,33 +83,31 @@ lb_fan_control_version_show(struct device *dev, struct device_attribute *attr, c · 18 unmodified lines | |||
| 84 | u16 major = 0, minor = 0, hotfix = 0, build = 0; | 83 | u16 major = 0, minor = 0, hotfix = 0, build = 0; |
| 85 | int ret; | 84 | int ret; |
| 86 | 85 | ||
| 87 | xe_pm_runtime_get(xe); | 86 | guard(xe_pm_runtime)(xe); |
| 88 | 87 | ||
| 89 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_CAPABILITY_STATUS, 0), | 88 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_CAPABILITY_STATUS, 0), |
| 90 | &cap, NULL); | 89 | &cap, NULL); |
| 91 | if (ret) | 90 | if (ret) |
| 92 | goto out; | 91 | return ret; |
| 93 | 92 | ||
| 94 | if (REG_FIELD_GET(V1_FAN_PROVISIONED, cap)) { | 93 | if (REG_FIELD_GET(V1_FAN_PROVISIONED, cap)) { |
| 95 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_LOW, 0), | 94 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_LOW, 0), |
| 96 | &ver_low, NULL); | 95 | &ver_low, NULL); |
| 97 | if (ret) | 96 | if (ret) |
| 98 | goto out; | 97 | return ret; |
| 99 | 98 | ||
| 100 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_HIGH, 0), | 99 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_HIGH, 0), |
| 101 | &ver_high, NULL); | 100 | &ver_high, NULL); |
| 102 | if (ret) | 101 | if (ret) |
| 103 | goto out; | 102 | return ret; |
| 104 | 103 | ||
| 105 | major = REG_FIELD_GET(MAJOR_VERSION_MASK, ver_low); | 104 | major = REG_FIELD_GET(MAJOR_VERSION_MASK, ver_low); |
| 106 | minor = REG_FIELD_GET(MINOR_VERSION_MASK, ver_low); | 105 | minor = REG_FIELD_GET(MINOR_VERSION_MASK, ver_low); |
| 107 | hotfix = REG_FIELD_GET(HOTFIX_VERSION_MASK, ver_high); | 106 | hotfix = REG_FIELD_GET(HOTFIX_VERSION_MASK, ver_high); |
| 108 | build = REG_FIELD_GET(BUILD_VERSION_MASK, ver_high); | 107 | build = REG_FIELD_GET(BUILD_VERSION_MASK, ver_high); |
| 109 | } | 108 | } |
| 110 | out: | ||
| 111 | xe_pm_runtime_put(xe); | ||
| 112 | 109 | ||
| 113 | return ret ?: sysfs_emit(buf, "%u.%u.%u.%u\n", major, minor, hotfix, build); | 110 | return sysfs_emit(buf, "%u.%u.%u.%u\n", major, minor, hotfix, build); |
| 114 | } | 111 | } |
| 115 | static DEVICE_ATTR_ADMIN_RO(lb_fan_control_version); | 112 | static DEVICE_ATTR_ADMIN_RO(lb_fan_control_version); |
| 116 | 113 | ||
| @@ -123,33 +120,31 @@ lb_voltage_regulator_version_show(struct device *dev, struct device_attribute *a · 6 unmodified lines | |||
| 123 | u16 major = 0, minor = 0, hotfix = 0, build = 0; | 120 | u16 major = 0, minor = 0, hotfix = 0, build = 0; |
| 124 | int ret; | 121 | int ret; |
| 125 | 122 | ||
| 126 | xe_pm_runtime_get(xe); | 123 | guard(xe_pm_runtime)(xe); |
| 127 | 124 | ||
| 128 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_CAPABILITY_STATUS, 0), | 125 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_CAPABILITY_STATUS, 0), |
| 129 | &cap, NULL); | 126 | &cap, NULL); |
| 130 | if (ret) | 127 | if (ret) |
| 131 | goto out; | 128 | return ret; |
| 132 | 129 | ||
| 133 | if (REG_FIELD_GET(VR_PARAMS_PROVISIONED, cap)) { | 130 | if (REG_FIELD_GET(VR_PARAMS_PROVISIONED, cap)) { |
| 134 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_LOW, 0), | 131 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_LOW, 0), |
| 135 | &ver_low, NULL); | 132 | &ver_low, NULL); |
| 136 | if (ret) | 133 | if (ret) |
| 137 | goto out; | 134 | return ret; |
| 138 | 135 | ||
| 139 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_HIGH, 0), | 136 | ret = xe_pcode_read(root, PCODE_MBOX(PCODE_LATE_BINDING, GET_VERSION_HIGH, 0), |
| 140 | &ver_high, NULL); | 137 | &ver_high, NULL); |
| 141 | if (ret) | 138 | if (ret) |
| 142 | goto out; | 139 | return ret; |
| 143 | 140 | ||
| 144 | major = REG_FIELD_GET(MAJOR_VERSION_MASK, ver_low); | 141 | major = REG_FIELD_GET(MAJOR_VERSION_MASK, ver_low); |
| 145 | minor = REG_FIELD_GET(MINOR_VERSION_MASK, ver_low); | 142 | minor = REG_FIELD_GET(MINOR_VERSION_MASK, ver_low); |
| 146 | hotfix = REG_FIELD_GET(HOTFIX_VERSION_MASK, ver_high); | 143 | hotfix = REG_FIELD_GET(HOTFIX_VERSION_MASK, ver_high); |
| 147 | build = REG_FIELD_GET(BUILD_VERSION_MASK, ver_high); | 144 | build = REG_FIELD_GET(BUILD_VERSION_MASK, ver_high); |
| 148 | } | 145 | } |
| 149 | out: | ||
| 150 | xe_pm_runtime_put(xe); | ||
| 151 | 146 | ||
| 152 | return ret ?: sysfs_emit(buf, "%u.%u.%u.%u\n", major, minor, hotfix, build); | 147 | return sysfs_emit(buf, "%u.%u.%u.%u\n", major, minor, hotfix, build); |
| 153 | } | 148 | } |
| 154 | static DEVICE_ATTR_ADMIN_RO(lb_voltage_regulator_version); | 149 | static DEVICE_ATTR_ADMIN_RO(lb_voltage_regulator_version); |
| 155 | 150 | ||
| @@ -233,9 +228,8 @@ auto_link_downgrade_capable_show(struct device *dev, struct device_attribute *at · 77 unmodified lines | |||
| 233 | struct xe_device *xe = pdev_to_xe_device(pdev); | 228 | struct xe_device *xe = pdev_to_xe_device(pdev); |
| 234 | u32 cap, val; | 229 | u32 cap, val; |
| 235 | 230 | ||
| 236 | xe_pm_runtime_get(xe); | 231 | guard(xe_pm_runtime)(xe); |
| 237 | val = xe_mmio_read32(xe_root_tile_mmio(xe), BMG_PCIE_CAP); | 232 | val = xe_mmio_read32(xe_root_tile_mmio(xe), BMG_PCIE_CAP); |
| 238 | xe_pm_runtime_put(xe); | ||
| 239 | 233 | ||
| 240 | cap = REG_FIELD_GET(LINK_DOWNGRADE, val); | 234 | cap = REG_FIELD_GET(LINK_DOWNGRADE, val); |
| 241 | return sysfs_emit(buf, "%u\n", cap == DOWNGRADE_CAPABLE); | 235 | return sysfs_emit(buf, "%u\n", cap == DOWNGRADE_CAPABLE); |
| @@ -251,11 +245,10 @@ auto_link_downgrade_status_show(struct device *dev, struct device_attribute *att · 9 unmodified lines | |||
| 251 | u32 val = 0; | 245 | u32 val = 0; |
| 252 | int ret; | 246 | int ret; |
| 253 | 247 | ||
| 254 | xe_pm_runtime_get(xe); | 248 | guard(xe_pm_runtime)(xe); |
| 255 | ret = xe_pcode_read(xe_device_get_root_tile(xe), | 249 | ret = xe_pcode_read(xe_device_get_root_tile(xe), |
| 256 | PCODE_MBOX(DGFX_PCODE_STATUS, DGFX_GET_INIT_STATUS, 0), | 250 | PCODE_MBOX(DGFX_PCODE_STATUS, DGFX_GET_INIT_STATUS, 0), |
| 257 | &val, NULL); | 251 | &val, NULL); |
| 258 | xe_pm_runtime_put(xe); | ||
| 259 | 252 | ||
| 260 | return ret ?: sysfs_emit(buf, "%u\n", REG_FIELD_GET(DGFX_LINK_DOWNGRADE_STATUS, val)); | 253 | return ret ?: sysfs_emit(buf, "%u\n", REG_FIELD_GET(DGFX_LINK_DOWNGRADE_STATUS, val)); |
| 261 | } | 254 | } |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | |||
| 17 | #include "xe_late_bind_fw_types.h" | 17 | #include "xe_late_bind_fw_types.h" |
| 18 | #include "xe_lmtt_types.h" | 18 | #include "xe_lmtt_types.h" |
| 19 | #include "xe_memirq_types.h" | 19 | #include "xe_memirq_types.h" |
| 20 | #include "xe_mert.h" | ||
| 20 | #include "xe_oa_types.h" | 21 | #include "xe_oa_types.h" |
| 21 | #include "xe_pagefault_types.h" | 22 | #include "xe_pagefault_types.h" |
| 22 | #include "xe_platform_types.h" | 23 | #include "xe_platform_types.h" |
| @@ -183,6 +184,13 @@ struct xe_tile { · 160 unmodified lines | |||
| 183 | * Media GT shares a pool with its primary GT. | 184 | * Media GT shares a pool with its primary GT. |
| 184 | */ | 185 | */ |
| 185 | struct xe_sa_manager *kernel_bb_pool; | 186 | struct xe_sa_manager *kernel_bb_pool; |
| 187 | |||
| 188 | /** | ||
| 189 | * @mem.reclaim_pool: Pool for PRLs allocated. | ||
| 190 | * | ||
| 191 | * Only main GT has page reclaim list allocations. | ||
| 192 | */ | ||
| 193 | struct xe_sa_manager *reclaim_pool; | ||
| 186 | } mem; | 194 | } mem; |
| 187 | 195 | ||
| 188 | /** @sriov: tile level virtualization data */ | 196 | /** @sriov: tile level virtualization data */ |
| @@ -219,6 +227,9 @@ struct xe_tile { · 30 unmodified lines | |||
| 219 | 227 | ||
| 220 | /** @debugfs: debugfs directory associated with this tile */ | 228 | /** @debugfs: debugfs directory associated with this tile */ |
| 221 | struct dentry *debugfs; | 229 | struct dentry *debugfs; |
| 230 | |||
| 231 | /** @mert: MERT-related data */ | ||
| 232 | struct xe_mert mert; | ||
| 222 | }; | 233 | }; |
| 223 | 234 | ||
| 224 | /** | 235 | /** |
| @@ -285,6 +296,8 @@ struct xe_device { · 60 unmodified lines | |||
| 285 | u8 has_asid:1; | 296 | u8 has_asid:1; |
| 286 | /** @info.has_atomic_enable_pte_bit: Device has atomic enable PTE bit */ | 297 | /** @info.has_atomic_enable_pte_bit: Device has atomic enable PTE bit */ |
| 287 | u8 has_atomic_enable_pte_bit:1; | 298 | u8 has_atomic_enable_pte_bit:1; |
| 299 | /** @info.has_cached_pt: Supports caching pagetable */ | ||
| 300 | u8 has_cached_pt:1; | ||
| 288 | /** @info.has_device_atomics_on_smem: Supports device atomics on SMEM */ | 301 | /** @info.has_device_atomics_on_smem: Supports device atomics on SMEM */ |
| 289 | u8 has_device_atomics_on_smem:1; | 302 | u8 has_device_atomics_on_smem:1; |
| 290 | /** @info.has_fan_control: Device supports fan control */ | 303 | /** @info.has_fan_control: Device supports fan control */ |
| @@ -297,6 +310,8 @@ struct xe_device { · 6 unmodified lines | |||
| 297 | u8 has_heci_cscfi:1; | 310 | u8 has_heci_cscfi:1; |
| 298 | /** @info.has_heci_gscfi: device has heci gscfi */ | 311 | /** @info.has_heci_gscfi: device has heci gscfi */ |
| 299 | u8 has_heci_gscfi:1; | 312 | u8 has_heci_gscfi:1; |
| 313 | /** @info.has_i2c: Device has I2C controller */ | ||
| 314 | u8 has_i2c:1; | ||
| 300 | /** @info.has_late_bind: Device has firmware late binding support */ | 315 | /** @info.has_late_bind: Device has firmware late binding support */ |
| 301 | u8 has_late_bind:1; | 316 | u8 has_late_bind:1; |
| 302 | /** @info.has_llc: Device has a shared CPU+GPU last level cache */ | 317 | /** @info.has_llc: Device has a shared CPU+GPU last level cache */ |
| @@ -307,6 +322,12 @@ struct xe_device { · 4 unmodified lines | |||
| 307 | u8 has_mbx_power_limits:1; | 322 | u8 has_mbx_power_limits:1; |
| 308 | /** @info.has_mem_copy_instr: Device supports MEM_COPY instruction */ | 323 | /** @info.has_mem_copy_instr: Device supports MEM_COPY instruction */ |
| 309 | u8 has_mem_copy_instr:1; | 324 | u8 has_mem_copy_instr:1; |
| 325 | /** @info.has_mert: Device has standalone MERT */ | ||
| 326 | u8 has_mert:1; | ||
| 327 | /** @info.has_page_reclaim_hw_assist: Device supports page reclamation feature */ | ||
| 328 | u8 has_page_reclaim_hw_assist:1; | ||
| 329 | /** @info.has_pre_prod_wa: Pre-production workarounds still present in driver */ | ||
| 330 | u8 has_pre_prod_wa:1; | ||
| 310 | /** @info.has_pxp: Device has PXP support */ | 331 | /** @info.has_pxp: Device has PXP support */ |
| 311 | u8 has_pxp:1; | 332 | u8 has_pxp:1; |
| 312 | /** @info.has_range_tlb_inval: Has range based TLB invalidations */ | 333 | /** @info.has_range_tlb_inval: Has range based TLB invalidations */ |
| @@ -605,6 +626,12 @@ struct xe_device { · 292 unmodified lines | |||
| 605 | /** @atomic_svm_timeslice_ms: Atomic SVM fault timeslice MS */ | 626 | /** @atomic_svm_timeslice_ms: Atomic SVM fault timeslice MS */ |
| 606 | u32 atomic_svm_timeslice_ms; | 627 | u32 atomic_svm_timeslice_ms; |
| 607 | 628 | ||
| 629 | /** @min_run_period_lr_ms: LR VM (preempt fence mode) timeslice */ | ||
| 630 | u32 min_run_period_lr_ms; | ||
| 631 | |||
| 632 | /** @min_run_period_pf_ms: LR VM (page fault mode) timeslice */ | ||
| 633 | u32 min_run_period_pf_ms; | ||
| 634 | |||
| 608 | #ifdef TEST_VM_OPS_ERROR | 635 | #ifdef TEST_VM_OPS_ERROR |
| 609 | /** | 636 | /** |
| 610 | * @vm_inject_error_position: inject errors at different places in VM | 637 | * @vm_inject_error_position: inject errors at different places in VM |
| @@ -285,32 +285,31 @@ static struct xe_hw_engine *any_engine(struct xe_device *xe) · 284 unmodified lines | |||
| 285 | return NULL; | 285 | return NULL; |
| 286 | } | 286 | } |
| 287 | 287 | ||
| 288 | static bool force_wake_get_any_engine(struct xe_device *xe, | 288 | /* |
| 289 | struct xe_hw_engine **phwe, | 289 | * Pick any engine and grab its forcewake. On error phwe will be NULL and |
| 290 | unsigned int *pfw_ref) | 290 | * the returned forcewake reference will be invalid. Callers should check |
| 291 | * phwe against NULL. | ||
| 292 | */ | ||
| 293 | static struct xe_force_wake_ref force_wake_get_any_engine(struct xe_device *xe, | ||
| 294 | struct xe_hw_engine **phwe) | ||
| 291 | { | 295 | { |
| 292 | enum xe_force_wake_domains domain; | 296 | enum xe_force_wake_domains domain; |
| 293 | unsigned int fw_ref; | 297 | struct xe_force_wake_ref fw_ref = {}; |
| 294 | struct xe_hw_engine *hwe; | 298 | struct xe_hw_engine *hwe; |
| 295 | struct xe_force_wake *fw; | 299 | |
| 300 | *phwe = NULL; | ||
| 296 | 301 | ||
| 297 | hwe = any_engine(xe); | 302 | hwe = any_engine(xe); |
| 298 | if (!hwe) | 303 | if (!hwe) |
| 299 | return false; | 304 | return fw_ref; /* will be invalid */ |
| 300 | 305 | ||
| 301 | domain = xe_hw_engine_to_fw_domain(hwe); | 306 | domain = xe_hw_engine_to_fw_domain(hwe); |
| 302 | fw = gt_to_fw(hwe->gt); | ||
| 303 | |||
| 304 | fw_ref = xe_force_wake_get(fw, domain); | ||
| 305 | if (!xe_force_wake_ref_has_domain(fw_ref, domain)) { | ||
| 306 | xe_force_wake_put(fw, fw_ref); | ||
| 307 | return false; | ||
| 308 | } | ||
| 309 | 307 | ||
| 310 | *phwe = hwe; | 308 | fw_ref = xe_force_wake_constructor(gt_to_fw(hwe->gt), domain); |
| 311 | *pfw_ref = fw_ref; | 309 | if (xe_force_wake_ref_has_domain(fw_ref.domains, domain)) |
| 310 | *phwe = hwe; /* valid forcewake */ | ||
| 312 | 311 | ||
| 313 | return true; | 312 | return fw_ref; |
| 314 | } | 313 | } |
| 315 | 314 | ||
| 316 | static void show_run_ticks(struct drm_printer *p, struct drm_file *file) | 315 | static void show_run_ticks(struct drm_printer *p, struct drm_file *file) |
| @@ -322,7 +321,6 @@ static void show_run_ticks(struct drm_printer *p, struct drm_file *file) · 5 unmodified lines | |||
| 322 | struct xe_hw_engine *hwe; | 321 | struct xe_hw_engine *hwe; |
| 323 | struct xe_exec_queue *q; | 322 | struct xe_exec_queue *q; |
| 324 | u64 gpu_timestamp; | 323 | u64 gpu_timestamp; |
| 325 | unsigned int fw_ref; | ||
| 326 | 324 | ||
| 327 | /* | 325 | /* |
| 328 | * RING_TIMESTAMP registers are inaccessible in VF mode. | 326 | * RING_TIMESTAMP registers are inaccessible in VF mode. |
| @@ -339,29 +337,26 @@ static void show_run_ticks(struct drm_printer *p, struct drm_file *file) · 10 unmodified lines | |||
| 339 | wait_var_event(&xef->exec_queue.pending_removal, | 337 | wait_var_event(&xef->exec_queue.pending_removal, |
| 340 | !atomic_read(&xef->exec_queue.pending_removal)); | 338 | !atomic_read(&xef->exec_queue.pending_removal)); |
| 341 | 339 | ||
| 342 | xe_pm_runtime_get(xe); | 340 | scoped_guard(xe_pm_runtime, xe) { |
| 343 | if (!force_wake_get_any_engine(xe, &hwe, &fw_ref)) { | 341 | CLASS(xe_force_wake_release_only, fw_ref)(force_wake_get_any_engine(xe, &hwe)); |
| 344 | xe_pm_runtime_put(xe); | 342 | if (!hwe) |
| 345 | return; | 343 | return; |
| 346 | } | ||
| 347 | |||
| 348 | /* Accumulate all the exec queues from this client */ | ||
| 349 | mutex_lock(&xef->exec_queue.lock); | ||
| 350 | xa_for_each(&xef->exec_queue.xa, i, q) { | ||
| 351 | xe_exec_queue_get(q); | ||
| 352 | mutex_unlock(&xef->exec_queue.lock); | ||
| 353 | |||
| 354 | xe_exec_queue_update_run_ticks(q); | ||
| 355 | 344 | ||
| 345 | /* Accumulate all the exec queues from this client */ | ||
| 356 | mutex_lock(&xef->exec_queue.lock); | 346 | mutex_lock(&xef->exec_queue.lock); |
| 357 | xe_exec_queue_put(q); | 347 | xa_for_each(&xef->exec_queue.xa, i, q) { |
| 358 | } | 348 | xe_exec_queue_get(q); |
| 359 | mutex_unlock(&xef->exec_queue.lock); | 349 | mutex_unlock(&xef->exec_queue.lock); |
| 360 | 350 | ||
| 361 | gpu_timestamp = xe_hw_engine_read_timestamp(hwe); | 351 | xe_exec_queue_update_run_ticks(q); |
| 362 | 352 | ||
| 363 | xe_force_wake_put(gt_to_fw(hwe->gt), fw_ref); | 353 | mutex_lock(&xef->exec_queue.lock); |
| 364 | xe_pm_runtime_put(xe); | 354 | xe_exec_queue_put(q); |
| 355 | } | ||
| 356 | mutex_unlock(&xef->exec_queue.lock); | ||
| 357 | |||
| 358 | gpu_timestamp = xe_hw_engine_read_timestamp(hwe); | ||
| 359 | } | ||
| 365 | 360 | ||
| 366 | for (class = 0; class < XE_ENGINE_CLASS_MAX; class++) { | 361 | for (class = 0; class < XE_ENGINE_CLASS_MAX; class++) { |
| 367 | const char *class_name; | 362 | const char *class_name; |
| @@ -121,7 +121,7 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) · 120 unmodified lines | |||
| 121 | u64 addresses[XE_HW_ENGINE_MAX_INSTANCE]; | 121 | u64 addresses[XE_HW_ENGINE_MAX_INSTANCE]; |
| 122 | struct drm_gpuvm_exec vm_exec = {.extra.fn = xe_exec_fn}; | 122 | struct drm_gpuvm_exec vm_exec = {.extra.fn = xe_exec_fn}; |
| 123 | struct drm_exec *exec = &vm_exec.exec; | 123 | struct drm_exec *exec = &vm_exec.exec; |
| 124 | u32 i, num_syncs, num_ufence = 0; | 124 | u32 i, num_syncs, num_in_sync = 0, num_ufence = 0; |
| 125 | struct xe_validation_ctx ctx; | 125 | struct xe_validation_ctx ctx; |
| 126 | struct xe_sched_job *job; | 126 | struct xe_sched_job *job; |
| 127 | struct xe_vm *vm; | 127 | struct xe_vm *vm; |
| @@ -183,6 +183,9 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) · 55 unmodified lines | |||
| 183 | 183 | ||
| 184 | if (xe_sync_is_ufence(&syncs[num_syncs])) | 184 | if (xe_sync_is_ufence(&syncs[num_syncs])) |
| 185 | num_ufence++; | 185 | num_ufence++; |
| 186 | |||
| 187 | if (!num_in_sync && xe_sync_needs_wait(&syncs[num_syncs])) | ||
| 188 | num_in_sync++; | ||
| 186 | } | 189 | } |
| 187 | 190 | ||
| 188 | if (XE_IOCTL_DBG(xe, num_ufence > 1)) { | 191 | if (XE_IOCTL_DBG(xe, num_ufence > 1)) { |
| @@ -203,7 +206,9 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file) · 14 unmodified lines | |||
| 203 | mode = xe_hw_engine_group_find_exec_mode(q); | 206 | mode = xe_hw_engine_group_find_exec_mode(q); |
| 204 | 207 | ||
| 205 | if (mode == EXEC_MODE_DMA_FENCE) { | 208 | if (mode == EXEC_MODE_DMA_FENCE) { |
| 206 | err = xe_hw_engine_group_get_mode(group, mode, &previous_mode); | 209 | err = xe_hw_engine_group_get_mode(group, mode, &previous_mode, |
| 210 | syncs, num_in_sync ? | ||
| 211 | num_syncs : 0); | ||
| 207 | if (err) | 212 | if (err) |
| 208 | goto err_syncs; | 213 | goto err_syncs; |
| 209 | } | 214 | } |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include <drm/drm_syncobj.h> | 13 | #include <drm/drm_syncobj.h> |
| 14 | #include <uapi/drm/xe_drm.h> | 14 | #include <uapi/drm/xe_drm.h> |
| 15 | 15 | ||
| 16 | #include "xe_bo.h" | ||
| 16 | #include "xe_dep_scheduler.h" | 17 | #include "xe_dep_scheduler.h" |
| 17 | #include "xe_device.h" | 18 | #include "xe_device.h" |
| 18 | #include "xe_gt.h" | 19 | #include "xe_gt.h" |
| @@ -53,6 +54,54 @@ · 34 unmodified lines | |||
| 53 | * the ring operations the different engine classes support. | 54 | * the ring operations the different engine classes support. |
| 54 | */ | 55 | */ |
| 55 | 56 | ||
| 57 | /** | ||
| 58 | * DOC: Multi Queue Group | ||
| 59 | * | ||
| 60 | * Multi Queue Group is another mode of execution supported by the compute | ||
| 61 | * and blitter copy command streamers (CCS and BCS, respectively). It is | ||
| 62 | * an enhancement of the existing hardware architecture and leverages the | ||
| 63 | * same submission model. It enables support for efficient, parallel | ||
| 64 | * execution of multiple queues within a single shared context. The multi | ||
| 65 | * queue group functionality is only supported with GuC submission backend. | ||
| 66 | * All the queues of a group must use the same address space (VM). | ||
| 67 | * | ||
| 68 | * The DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE execution queue property | ||
| 69 | * supports creating a multi queue group and adding queues to a queue group. | ||
| 70 | * | ||
| 71 | * The XE_EXEC_QUEUE_CREATE ioctl call with above property with value field | ||
| 72 | * set to DRM_XE_MULTI_GROUP_CREATE, will create a new multi queue group with | ||
| 73 | * the queue being created as the primary queue (aka q0) of the group. To add | ||
| 74 | * secondary queues to the group, they need to be created with the above | ||
| 75 | * property with id of the primary queue as the value. The properties of | ||
| 76 | * the primary queue (like priority, time slice) applies to the whole group. | ||
| 77 | * So, these properties can't be set for secondary queues of a group. | ||
| 78 | * | ||
| 79 | * The hardware does not support removing a queue from a multi-queue group. | ||
| 80 | * However, queues can be dynamically added to the group. A group can have | ||
| 81 | * up to 64 queues. To support this, XeKMD holds references to LRCs of the | ||
| 82 | * queues even after the queues are destroyed by the user until the whole | ||
| 83 | * group is destroyed. The secondary queues hold a reference to the primary | ||
| 84 | * queue thus preventing the group from being destroyed when user destroys | ||
| 85 | * the primary queue. Once the primary queue is destroyed, secondary queues | ||
| 86 | * can't be added to the queue group, but they can continue to submit the | ||
| 87 | * jobs if the DRM_XE_MULTI_GROUP_KEEP_ACTIVE flag is set during the multi | ||
| 88 | * queue group creation. | ||
| 89 | * | ||
| 90 | * The queues of a multi queue group can set their priority within the group | ||
| 91 | * through the DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY property. | ||
| 92 | * This multi queue priority can also be set dynamically through the | ||
| 93 | * XE_EXEC_QUEUE_SET_PROPERTY ioctl. This is the only other property | ||
| 94 | * supported by the secondary queues of a multi queue group, other than | ||
| 95 | * DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE. | ||
| 96 | * | ||
| 97 | * When GuC reports an error on any of the queues of a multi queue group, | ||
| 98 | * the queue cleanup mechanism is invoked for all the queues of the group | ||
| 99 | * as hardware cannot make progress on the multi queue context. | ||
| 100 | * | ||
| 101 | * Refer :ref:`multi-queue-group-guc-interface` for multi queue group GuC | ||
| 102 | * interface. | ||
| 103 | */ | ||
| 104 | |||
| 56 | enum xe_exec_queue_sched_prop { | 105 | enum xe_exec_queue_sched_prop { |
| 57 | XE_EXEC_QUEUE_JOB_TIMEOUT = 0, | 106 | XE_EXEC_QUEUE_JOB_TIMEOUT = 0, |
| 58 | XE_EXEC_QUEUE_TIMESLICE = 1, | 107 | XE_EXEC_QUEUE_TIMESLICE = 1, |
| @@ -61,7 +110,35 @@ enum xe_exec_queue_sched_prop { · 2 unmodified lines | |||
| 61 | }; | 110 | }; |
| 62 | 111 | ||
| 63 | static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue *q, | 112 | static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue *q, |
| 64 | u64 extensions, int ext_number); | 113 | u64 extensions); |
| 114 | |||
| 115 | static void xe_exec_queue_group_cleanup(struct xe_exec_queue *q) | ||
| 116 | { | ||
| 117 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 118 | struct xe_lrc *lrc; | ||
| 119 | unsigned long idx; | ||
| 120 | |||
| 121 | if (xe_exec_queue_is_multi_queue_secondary(q)) { | ||
| 122 | /* | ||
| 123 | * Put pairs with get from xe_exec_queue_lookup() call | ||
| 124 | * in xe_exec_queue_group_validate(). | ||
| 125 | */ | ||
| 126 | xe_exec_queue_put(xe_exec_queue_multi_queue_primary(q)); | ||
| 127 | return; | ||
| 128 | } | ||
| 129 | |||
| 130 | if (!group) | ||
| 131 | return; | ||
| 132 | |||
| 133 | /* Primary queue cleanup */ | ||
| 134 | xa_for_each(&group->xa, idx, lrc) | ||
| 135 | xe_lrc_put(lrc); | ||
| 136 | |||
| 137 | xa_destroy(&group->xa); | ||
| 138 | mutex_destroy(&group->list_lock); | ||
| 139 | xe_bo_unpin_map_no_vm(group->cgp_bo); | ||
| 140 | kfree(group); | ||
| 141 | } | ||
| 65 | 142 | ||
| 66 | static void __xe_exec_queue_free(struct xe_exec_queue *q) | 143 | static void __xe_exec_queue_free(struct xe_exec_queue *q) |
| 67 | { | 144 | { |
| @@ -73,12 +150,17 @@ static void __xe_exec_queue_free(struct xe_exec_queue *q) · 5 unmodified lines | |||
| 73 | 150 | ||
| 74 | if (xe_exec_queue_uses_pxp(q)) | 151 | if (xe_exec_queue_uses_pxp(q)) |
| 75 | xe_pxp_exec_queue_remove(gt_to_xe(q->gt)->pxp, q); | 152 | xe_pxp_exec_queue_remove(gt_to_xe(q->gt)->pxp, q); |
| 153 | |||
| 154 | if (xe_exec_queue_is_multi_queue(q)) | ||
| 155 | xe_exec_queue_group_cleanup(q); | ||
| 156 | |||
| 76 | if (q->vm) | 157 | if (q->vm) |
| 77 | xe_vm_put(q->vm); | 158 | xe_vm_put(q->vm); |
| 78 | 159 | ||
| 79 | if (q->xef) | 160 | if (q->xef) |
| 80 | xe_file_put(q->xef); | 161 | xe_file_put(q->xef); |
| 81 | 162 | ||
| 163 | kvfree(q->replay_state); | ||
| 82 | kfree(q); | 164 | kfree(q); |
| 83 | } | 165 | } |
| 84 | 166 | ||
| @@ -147,6 +229,7 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe, · 62 unmodified lines | |||
| 147 | INIT_LIST_HEAD(&q->multi_gt_link); | 229 | INIT_LIST_HEAD(&q->multi_gt_link); |
| 148 | INIT_LIST_HEAD(&q->hw_engine_group_link); | 230 | INIT_LIST_HEAD(&q->hw_engine_group_link); |
| 149 | INIT_LIST_HEAD(&q->pxp.link); | 231 | INIT_LIST_HEAD(&q->pxp.link); |
| 232 | q->multi_queue.priority = XE_MULTI_QUEUE_PRIORITY_NORMAL; | ||
| 150 | 233 | ||
| 151 | q->sched_props.timeslice_us = hwe->eclass->sched_props.timeslice_us; | 234 | q->sched_props.timeslice_us = hwe->eclass->sched_props.timeslice_us; |
| 152 | q->sched_props.preempt_timeout_us = | 235 | q->sched_props.preempt_timeout_us = |
| @@ -175,7 +258,7 @@ static struct xe_exec_queue *__xe_exec_queue_alloc(struct xe_device *xe, · 22 unmodified lines | |||
| 175 | * may set q->usm, must come before xe_lrc_create(), | 258 | * may set q->usm, must come before xe_lrc_create(), |
| 176 | * may overwrite q->sched_props, must come before q->ops->init() | 259 | * may overwrite q->sched_props, must come before q->ops->init() |
| 177 | */ | 260 | */ |
| 178 | err = exec_queue_user_extensions(xe, q, extensions, 0); | 261 | err = exec_queue_user_extensions(xe, q, extensions); |
| 179 | if (err) { | 262 | if (err) { |
| 180 | __xe_exec_queue_free(q); | 263 | __xe_exec_queue_free(q); |
| 181 | return ERR_PTR(err); | 264 | return ERR_PTR(err); |
| @@ -225,8 +308,8 @@ static int __xe_exec_queue_init(struct xe_exec_queue *q, u32 exec_queue_flags) · 43 unmodified lines | |||
| 225 | struct xe_lrc *lrc; | 308 | struct xe_lrc *lrc; |
| 226 | 309 | ||
| 227 | xe_gt_sriov_vf_wait_valid_ggtt(q->gt); | 310 | xe_gt_sriov_vf_wait_valid_ggtt(q->gt); |
| 228 | lrc = xe_lrc_create(q->hwe, q->vm, xe_lrc_ring_size(), | 311 | lrc = xe_lrc_create(q->hwe, q->vm, q->replay_state, |
| 229 | q->msix_vec, flags); | 312 | xe_lrc_ring_size(), q->msix_vec, flags); |
| 230 | if (IS_ERR(lrc)) { | 313 | if (IS_ERR(lrc)) { |
| 231 | err = PTR_ERR(lrc); | 314 | err = PTR_ERR(lrc); |
| 232 | goto err_lrc; | 315 | goto err_lrc; |
| @@ -383,6 +466,26 @@ struct xe_exec_queue *xe_exec_queue_create_bind(struct xe_device *xe, · 150 unmodified lines | |||
| 383 | } | 466 | } |
| 384 | ALLOW_ERROR_INJECTION(xe_exec_queue_create_bind, ERRNO); | 467 | ALLOW_ERROR_INJECTION(xe_exec_queue_create_bind, ERRNO); |
| 385 | 468 | ||
| 469 | static void xe_exec_queue_group_kill(struct kref *ref) | ||
| 470 | { | ||
| 471 | struct xe_exec_queue_group *group = container_of(ref, struct xe_exec_queue_group, | ||
| 472 | kill_refcount); | ||
| 473 | xe_exec_queue_kill(group->primary); | ||
| 474 | } | ||
| 475 | |||
| 476 | static inline void xe_exec_queue_group_kill_get(struct xe_exec_queue_group *group) | ||
| 477 | { | ||
| 478 | kref_get(&group->kill_refcount); | ||
| 479 | } | ||
| 480 | |||
| 481 | void xe_exec_queue_group_kill_put(struct xe_exec_queue_group *group) | ||
| 482 | { | ||
| 483 | if (!group) | ||
| 484 | return; | ||
| 485 | |||
| 486 | kref_put(&group->kill_refcount, xe_exec_queue_group_kill); | ||
| 487 | } | ||
| 488 | |||
| 386 | void xe_exec_queue_destroy(struct kref *ref) | 489 | void xe_exec_queue_destroy(struct kref *ref) |
| 387 | { | 490 | { |
| 388 | struct xe_exec_queue *q = container_of(ref, struct xe_exec_queue, refcount); | 491 | struct xe_exec_queue *q = container_of(ref, struct xe_exec_queue, refcount); |
| @@ -567,6 +670,217 @@ exec_queue_set_pxp_type(struct xe_device *xe, struct xe_exec_queue *q, u64 value · 178 unmodified lines | |||
| 567 | return xe_pxp_exec_queue_set_type(xe->pxp, q, DRM_XE_PXP_TYPE_HWDRM); | 670 | return xe_pxp_exec_queue_set_type(xe->pxp, q, DRM_XE_PXP_TYPE_HWDRM); |
| 568 | } | 671 | } |
| 569 | 672 | ||
| 673 | static int exec_queue_set_hang_replay_state(struct xe_device *xe, | ||
| 674 | struct xe_exec_queue *q, | ||
| 675 | u64 value) | ||
| 676 | { | ||
| 677 | size_t size = xe_gt_lrc_hang_replay_size(q->gt, q->class); | ||
| 678 | u64 __user *address = u64_to_user_ptr(value); | ||
| 679 | void *ptr; | ||
| 680 | |||
| 681 | ptr = vmemdup_user(address, size); | ||
| 682 | if (XE_IOCTL_DBG(xe, IS_ERR(ptr))) | ||
| 683 | return PTR_ERR(ptr); | ||
| 684 | |||
| 685 | q->replay_state = ptr; | ||
| 686 | |||
| 687 | return 0; | ||
| 688 | } | ||
| 689 | |||
| 690 | static int xe_exec_queue_group_init(struct xe_device *xe, struct xe_exec_queue *q) | ||
| 691 | { | ||
| 692 | struct xe_tile *tile = gt_to_tile(q->gt); | ||
| 693 | struct xe_exec_queue_group *group; | ||
| 694 | struct xe_bo *bo; | ||
| 695 | |||
| 696 | group = kzalloc(sizeof(*group), GFP_KERNEL); | ||
| 697 | if (!group) | ||
| 698 | return -ENOMEM; | ||
| 699 | |||
| 700 | bo = xe_bo_create_pin_map_novm(xe, tile, SZ_4K, ttm_bo_type_kernel, | ||
| 701 | XE_BO_FLAG_VRAM_IF_DGFX(tile) | | ||
| 702 | XE_BO_FLAG_PINNED_LATE_RESTORE | | ||
| 703 | XE_BO_FLAG_FORCE_USER_VRAM | | ||
| 704 | XE_BO_FLAG_GGTT_INVALIDATE | | ||
| 705 | XE_BO_FLAG_GGTT, false); | ||
| 706 | if (IS_ERR(bo)) { | ||
| 707 | drm_err(&xe->drm, "CGP bo allocation for queue group failed: %ld\n", | ||
| 708 | PTR_ERR(bo)); | ||
| 709 | kfree(group); | ||
| 710 | return PTR_ERR(bo); | ||
| 711 | } | ||
| 712 | |||
| 713 | xe_map_memset(xe, &bo->vmap, 0, 0, SZ_4K); | ||
| 714 | |||
| 715 | group->primary = q; | ||
| 716 | group->cgp_bo = bo; | ||
| 717 | INIT_LIST_HEAD(&group->list); | ||
| 718 | kref_init(&group->kill_refcount); | ||
| 719 | xa_init_flags(&group->xa, XA_FLAGS_ALLOC1); | ||
| 720 | mutex_init(&group->list_lock); | ||
| 721 | q->multi_queue.group = group; | ||
| 722 | |||
| 723 | /* group->list_lock is used in submission backend */ | ||
| 724 | if (IS_ENABLED(CONFIG_LOCKDEP)) { | ||
| 725 | fs_reclaim_acquire(GFP_KERNEL); | ||
| 726 | might_lock(&group->list_lock); | ||
| 727 | fs_reclaim_release(GFP_KERNEL); | ||
| 728 | } | ||
| 729 | |||
| 730 | return 0; | ||
| 731 | } | ||
| 732 | |||
| 733 | static inline bool xe_exec_queue_supports_multi_queue(struct xe_exec_queue *q) | ||
| 734 | { | ||
| 735 | return q->gt->info.multi_queue_engine_class_mask & BIT(q->class); | ||
| 736 | } | ||
| 737 | |||
| 738 | static int xe_exec_queue_group_validate(struct xe_device *xe, struct xe_exec_queue *q, | ||
| 739 | u32 primary_id) | ||
| 740 | { | ||
| 741 | struct xe_exec_queue_group *group; | ||
| 742 | struct xe_exec_queue *primary; | ||
| 743 | int ret; | ||
| 744 | |||
| 745 | /* | ||
| 746 | * Get from below xe_exec_queue_lookup() pairs with put | ||
| 747 | * in xe_exec_queue_group_cleanup(). | ||
| 748 | */ | ||
| 749 | primary = xe_exec_queue_lookup(q->vm->xef, primary_id); | ||
| 750 | if (XE_IOCTL_DBG(xe, !primary)) | ||
| 751 | return -ENOENT; | ||
| 752 | |||
| 753 | if (XE_IOCTL_DBG(xe, !xe_exec_queue_is_multi_queue_primary(primary)) || | ||
| 754 | XE_IOCTL_DBG(xe, q->vm != primary->vm) || | ||
| 755 | XE_IOCTL_DBG(xe, q->logical_mask != primary->logical_mask)) { | ||
| 756 | ret = -EINVAL; | ||
| 757 | goto put_primary; | ||
| 758 | } | ||
| 759 | |||
| 760 | group = primary->multi_queue.group; | ||
| 761 | q->multi_queue.valid = true; | ||
| 762 | q->multi_queue.group = group; | ||
| 763 | |||
| 764 | return 0; | ||
| 765 | put_primary: | ||
| 766 | xe_exec_queue_put(primary); | ||
| 767 | return ret; | ||
| 768 | } | ||
| 769 | |||
| 770 | #define XE_MAX_GROUP_SIZE 64 | ||
| 771 | static int xe_exec_queue_group_add(struct xe_device *xe, struct xe_exec_queue *q) | ||
| 772 | { | ||
| 773 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 774 | u32 pos; | ||
| 775 | int err; | ||
| 776 | |||
| 777 | xe_assert(xe, xe_exec_queue_is_multi_queue_secondary(q)); | ||
| 778 | |||
| 779 | /* Primary queue holds a reference to LRCs of all secondary queues */ | ||
| 780 | err = xa_alloc(&group->xa, &pos, xe_lrc_get(q->lrc[0]), | ||
| 781 | XA_LIMIT(1, XE_MAX_GROUP_SIZE - 1), GFP_KERNEL); | ||
| 782 | if (XE_IOCTL_DBG(xe, err)) { | ||
| 783 | xe_lrc_put(q->lrc[0]); | ||
| 784 | |||
| 785 | /* It is invalid if queue group limit is exceeded */ | ||
| 786 | if (err == -EBUSY) | ||
| 787 | err = -EINVAL; | ||
| 788 | |||
| 789 | return err; | ||
| 790 | } | ||
| 791 | |||
| 792 | q->multi_queue.pos = pos; | ||
| 793 | |||
| 794 | if (group->primary->multi_queue.keep_active) { | ||
| 795 | xe_exec_queue_group_kill_get(group); | ||
| 796 | q->multi_queue.keep_active = true; | ||
| 797 | } | ||
| 798 | |||
| 799 | return 0; | ||
| 800 | } | ||
| 801 | |||
| 802 | static void xe_exec_queue_group_delete(struct xe_device *xe, struct xe_exec_queue *q) | ||
| 803 | { | ||
| 804 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 805 | struct xe_lrc *lrc; | ||
| 806 | |||
| 807 | xe_assert(xe, xe_exec_queue_is_multi_queue_secondary(q)); | ||
| 808 | |||
| 809 | lrc = xa_erase(&group->xa, q->multi_queue.pos); | ||
| 810 | xe_assert(xe, lrc); | ||
| 811 | xe_lrc_put(lrc); | ||
| 812 | |||
| 813 | if (q->multi_queue.keep_active) { | ||
| 814 | xe_exec_queue_group_kill_put(group); | ||
| 815 | q->multi_queue.keep_active = false; | ||
| 816 | } | ||
| 817 | } | ||
| 818 | |||
| 819 | static int exec_queue_set_multi_group(struct xe_device *xe, struct xe_exec_queue *q, | ||
| 820 | u64 value) | ||
| 821 | { | ||
| 822 | if (XE_IOCTL_DBG(xe, !xe_exec_queue_supports_multi_queue(q))) | ||
| 823 | return -ENODEV; | ||
| 824 | |||
| 825 | if (XE_IOCTL_DBG(xe, !xe_device_uc_enabled(xe))) | ||
| 826 | return -EOPNOTSUPP; | ||
| 827 | |||
| 828 | if (XE_IOCTL_DBG(xe, !q->vm->xef)) | ||
| 829 | return -EINVAL; | ||
| 830 | |||
| 831 | if (XE_IOCTL_DBG(xe, xe_exec_queue_is_parallel(q))) | ||
| 832 | return -EINVAL; | ||
| 833 | |||
| 834 | if (XE_IOCTL_DBG(xe, xe_exec_queue_is_multi_queue(q))) | ||
| 835 | return -EINVAL; | ||
| 836 | |||
| 837 | if (value & DRM_XE_MULTI_GROUP_CREATE) { | ||
| 838 | if (XE_IOCTL_DBG(xe, value & ~(DRM_XE_MULTI_GROUP_CREATE | | ||
| 839 | DRM_XE_MULTI_GROUP_KEEP_ACTIVE))) | ||
| 840 | return -EINVAL; | ||
| 841 | |||
| 842 | /* | ||
| 843 | * KEEP_ACTIVE is not supported in preempt fence mode as in that mode, | ||
| 844 | * VM_DESTROY ioctl expects all exec queues of that VM are already killed. | ||
| 845 | */ | ||
| 846 | if (XE_IOCTL_DBG(xe, (value & DRM_XE_MULTI_GROUP_KEEP_ACTIVE) && | ||
| 847 | xe_vm_in_preempt_fence_mode(q->vm))) | ||
| 848 | return -EINVAL; | ||
| 849 | |||
| 850 | q->multi_queue.valid = true; | ||
| 851 | q->multi_queue.is_primary = true; | ||
| 852 | q->multi_queue.pos = 0; | ||
| 853 | if (value & DRM_XE_MULTI_GROUP_KEEP_ACTIVE) | ||
| 854 | q->multi_queue.keep_active = true; | ||
| 855 | |||
| 856 | return 0; | ||
| 857 | } | ||
| 858 | |||
| 859 | /* While adding secondary queues, the upper 32 bits must be 0 */ | ||
| 860 | if (XE_IOCTL_DBG(xe, value & (~0ull << 32))) | ||
| 861 | return -EINVAL; | ||
| 862 | |||
| 863 | return xe_exec_queue_group_validate(xe, q, value); | ||
| 864 | } | ||
| 865 | |||
| 866 | static int exec_queue_set_multi_queue_priority(struct xe_device *xe, struct xe_exec_queue *q, | ||
| 867 | u64 value) | ||
| 868 | { | ||
| 869 | if (XE_IOCTL_DBG(xe, value > XE_MULTI_QUEUE_PRIORITY_HIGH)) | ||
| 870 | return -EINVAL; | ||
| 871 | |||
| 872 | /* For queue creation time (!q->xef) setting, just store the priority value */ | ||
| 873 | if (!q->xef) { | ||
| 874 | q->multi_queue.priority = value; | ||
| 875 | return 0; | ||
| 876 | } | ||
| 877 | |||
| 878 | if (!xe_exec_queue_is_multi_queue(q)) | ||
| 879 | return -EINVAL; | ||
| 880 | |||
| 881 | return q->ops->set_multi_queue_priority(q, value); | ||
| 882 | } | ||
| 883 | |||
| 570 | typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe, | 884 | typedef int (*xe_exec_queue_set_property_fn)(struct xe_device *xe, |
| 571 | struct xe_exec_queue *q, | 885 | struct xe_exec_queue *q, |
| 572 | u64 value); | 886 | u64 value); |
| @@ -575,11 +889,76 @@ static const xe_exec_queue_set_property_fn exec_queue_set_property_funcs[] = { · 2 unmodified lines | |||
| 575 | [DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY] = exec_queue_set_priority, | 889 | [DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY] = exec_queue_set_priority, |
| 576 | [DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE] = exec_queue_set_timeslice, | 890 | [DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE] = exec_queue_set_timeslice, |
| 577 | [DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE] = exec_queue_set_pxp_type, | 891 | [DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE] = exec_queue_set_pxp_type, |
| 892 | [DRM_XE_EXEC_QUEUE_SET_HANG_REPLAY_STATE] = exec_queue_set_hang_replay_state, | ||
| 893 | [DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP] = exec_queue_set_multi_group, | ||
| 894 | [DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY] = | ||
| 895 | exec_queue_set_multi_queue_priority, | ||
| 578 | }; | 896 | }; |
| 579 | 897 | ||
| 898 | int xe_exec_queue_set_property_ioctl(struct drm_device *dev, void *data, | ||
| 899 | struct drm_file *file) | ||
| 900 | { | ||
| 901 | struct xe_device *xe = to_xe_device(dev); | ||
| 902 | struct xe_file *xef = to_xe_file(file); | ||
| 903 | struct drm_xe_exec_queue_set_property *args = data; | ||
| 904 | struct xe_exec_queue *q; | ||
| 905 | int ret; | ||
| 906 | u32 idx; | ||
| 907 | |||
| 908 | if (XE_IOCTL_DBG(xe, args->reserved[0] || args->reserved[1])) | ||
| 909 | return -EINVAL; | ||
| 910 | |||
| 911 | if (XE_IOCTL_DBG(xe, args->property != | ||
| 912 | DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY)) | ||
| 913 | return -EINVAL; | ||
| 914 | |||
| 915 | q = xe_exec_queue_lookup(xef, args->exec_queue_id); | ||
| 916 | if (XE_IOCTL_DBG(xe, !q)) | ||
| 917 | return -ENOENT; | ||
| 918 | |||
| 919 | idx = array_index_nospec(args->property, | ||
| 920 | ARRAY_SIZE(exec_queue_set_property_funcs)); | ||
| 921 | ret = exec_queue_set_property_funcs[idx](xe, q, args->value); | ||
| 922 | if (XE_IOCTL_DBG(xe, ret)) | ||
| 923 | goto err_post_lookup; | ||
| 924 | |||
| 925 | xe_exec_queue_put(q); | ||
| 926 | return 0; | ||
| 927 | |||
| 928 | err_post_lookup: | ||
| 929 | xe_exec_queue_put(q); | ||
| 930 | return ret; | ||
| 931 | } | ||
| 932 | |||
| 933 | static int exec_queue_user_ext_check(struct xe_exec_queue *q, u64 properties) | ||
| 934 | { | ||
| 935 | u64 secondary_queue_valid_props = BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP) | | ||
| 936 | BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY); | ||
| 937 | |||
| 938 | /* | ||
| 939 | * Only MULTI_QUEUE_PRIORITY property is valid for secondary queues of a | ||
| 940 | * multi-queue group. | ||
| 941 | */ | ||
| 942 | if (xe_exec_queue_is_multi_queue_secondary(q) && | ||
| 943 | properties & ~secondary_queue_valid_props) | ||
| 944 | return -EINVAL; | ||
| 945 | |||
| 946 | return 0; | ||
| 947 | } | ||
| 948 | |||
| 949 | static int exec_queue_user_ext_check_final(struct xe_exec_queue *q, u64 properties) | ||
| 950 | { | ||
| 951 | /* MULTI_QUEUE_PRIORITY only applies to multi-queue group queues */ | ||
| 952 | if ((properties & BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY)) && | ||
| 953 | !(properties & BIT_ULL(DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP))) | ||
| 954 | return -EINVAL; | ||
| 955 | |||
| 956 | return 0; | ||
| 957 | } | ||
| 958 | |||
| 580 | static int exec_queue_user_ext_set_property(struct xe_device *xe, | 959 | static int exec_queue_user_ext_set_property(struct xe_device *xe, |
| 581 | struct xe_exec_queue *q, | 960 | struct xe_exec_queue *q, |
| 582 | u64 extension) | 961 | u64 extension, u64 *properties) |
| 583 | { | 962 | { |
| 584 | u64 __user *address = u64_to_user_ptr(extension); | 963 | u64 __user *address = u64_to_user_ptr(extension); |
| 585 | struct drm_xe_ext_set_property ext; | 964 | struct drm_xe_ext_set_property ext; |
| @@ -595,27 +974,35 @@ static int exec_queue_user_ext_set_property(struct xe_device *xe, · 9 unmodified lines | |||
| 595 | XE_IOCTL_DBG(xe, ext.pad) || | 974 | XE_IOCTL_DBG(xe, ext.pad) || |
| 596 | XE_IOCTL_DBG(xe, ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY && | 975 | XE_IOCTL_DBG(xe, ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY && |
| 597 | ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE && | 976 | ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE && |
| 598 | ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE)) | 977 | ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE && |
| 978 | ext.property != DRM_XE_EXEC_QUEUE_SET_HANG_REPLAY_STATE && | ||
| 979 | ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP && | ||
| 980 | ext.property != DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY)) | ||
| 599 | return -EINVAL; | 981 | return -EINVAL; |
| 600 | 982 | ||
| 601 | idx = array_index_nospec(ext.property, ARRAY_SIZE(exec_queue_set_property_funcs)); | 983 | idx = array_index_nospec(ext.property, ARRAY_SIZE(exec_queue_set_property_funcs)); |
| 602 | if (!exec_queue_set_property_funcs[idx]) | 984 | if (!exec_queue_set_property_funcs[idx]) |
| 603 | return -EINVAL; | 985 | return -EINVAL; |
| 604 | 986 | ||
| 987 | *properties |= BIT_ULL(idx); | ||
| 988 | err = exec_queue_user_ext_check(q, *properties); | ||
| 989 | if (XE_IOCTL_DBG(xe, err)) | ||
| 990 | return err; | ||
| 991 | |||
| 605 | return exec_queue_set_property_funcs[idx](xe, q, ext.value); | 992 | return exec_queue_set_property_funcs[idx](xe, q, ext.value); |
| 606 | } | 993 | } |
| 607 | 994 | ||
| 608 | typedef int (*xe_exec_queue_user_extension_fn)(struct xe_device *xe, | 995 | typedef int (*xe_exec_queue_user_extension_fn)(struct xe_device *xe, |
| 609 | struct xe_exec_queue *q, | 996 | struct xe_exec_queue *q, |
| 610 | u64 extension); | 997 | u64 extension, u64 *properties); |
| 611 | 998 | ||
| 612 | static const xe_exec_queue_user_extension_fn exec_queue_user_extension_funcs[] = { | 999 | static const xe_exec_queue_user_extension_fn exec_queue_user_extension_funcs[] = { |
| 613 | [DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY] = exec_queue_user_ext_set_property, | 1000 | [DRM_XE_EXEC_QUEUE_EXTENSION_SET_PROPERTY] = exec_queue_user_ext_set_property, |
| 614 | }; | 1001 | }; |
| 615 | 1002 | ||
| 616 | #define MAX_USER_EXTENSIONS 16 | 1003 | #define MAX_USER_EXTENSIONS 16 |
| 617 | static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue *q, | 1004 | static int __exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue *q, |
| 618 | u64 extensions, int ext_number) | 1005 | u64 extensions, int ext_number, u64 *properties) |
| 619 | { | 1006 | { |
| 620 | u64 __user *address = u64_to_user_ptr(extensions); | 1007 | u64 __user *address = u64_to_user_ptr(extensions); |
| 621 | struct drm_xe_user_extension ext; | 1008 | struct drm_xe_user_extension ext; |
| @@ -636,13 +1023,36 @@ static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue · 14 unmodified lines | |||
| 636 | 1023 | ||
| 637 | idx = array_index_nospec(ext.name, | 1024 | idx = array_index_nospec(ext.name, |
| 638 | ARRAY_SIZE(exec_queue_user_extension_funcs)); | 1025 | ARRAY_SIZE(exec_queue_user_extension_funcs)); |
| 639 | err = exec_queue_user_extension_funcs[idx](xe, q, extensions); | 1026 | err = exec_queue_user_extension_funcs[idx](xe, q, extensions, properties); |
| 640 | if (XE_IOCTL_DBG(xe, err)) | 1027 | if (XE_IOCTL_DBG(xe, err)) |
| 641 | return err; | 1028 | return err; |
| 642 | 1029 | ||
| 643 | if (ext.next_extension) | 1030 | if (ext.next_extension) |
| 644 | return exec_queue_user_extensions(xe, q, ext.next_extension, | 1031 | return __exec_queue_user_extensions(xe, q, ext.next_extension, |
| 645 | ++ext_number); | 1032 | ++ext_number, properties); |
| 1033 | |||
| 1034 | return 0; | ||
| 1035 | } | ||
| 1036 | |||
| 1037 | static int exec_queue_user_extensions(struct xe_device *xe, struct xe_exec_queue *q, | ||
| 1038 | u64 extensions) | ||
| 1039 | { | ||
| 1040 | u64 properties = 0; | ||
| 1041 | int err; | ||
| 1042 | |||
| 1043 | err = __exec_queue_user_extensions(xe, q, extensions, 0, &properties); | ||
| 1044 | if (XE_IOCTL_DBG(xe, err)) | ||
| 1045 | return err; | ||
| 1046 | |||
| 1047 | err = exec_queue_user_ext_check_final(q, properties); | ||
| 1048 | if (XE_IOCTL_DBG(xe, err)) | ||
| 1049 | return err; | ||
| 1050 | |||
| 1051 | if (xe_exec_queue_is_multi_queue_primary(q)) { | ||
| 1052 | err = xe_exec_queue_group_init(xe, q); | ||
| 1053 | if (XE_IOCTL_DBG(xe, err)) | ||
| 1054 | return err; | ||
| 1055 | } | ||
| 646 | 1056 | ||
| 647 | return 0; | 1057 | return 0; |
| 648 | } | 1058 | } |
| @@ -798,12 +1208,18 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, · 149 unmodified lines | |||
| 798 | if (IS_ERR(q)) | 1208 | if (IS_ERR(q)) |
| 799 | return PTR_ERR(q); | 1209 | return PTR_ERR(q); |
| 800 | 1210 | ||
| 1211 | if (xe_exec_queue_is_multi_queue_secondary(q)) { | ||
| 1212 | err = xe_exec_queue_group_add(xe, q); | ||
| 1213 | if (XE_IOCTL_DBG(xe, err)) | ||
| 1214 | goto put_exec_queue; | ||
| 1215 | } | ||
| 1216 | |||
| 801 | if (xe_vm_in_preempt_fence_mode(vm)) { | 1217 | if (xe_vm_in_preempt_fence_mode(vm)) { |
| 802 | q->lr.context = dma_fence_context_alloc(1); | 1218 | q->lr.context = dma_fence_context_alloc(1); |
| 803 | 1219 | ||
| 804 | err = xe_vm_add_compute_exec_queue(vm, q); | 1220 | err = xe_vm_add_compute_exec_queue(vm, q); |
| 805 | if (XE_IOCTL_DBG(xe, err)) | 1221 | if (XE_IOCTL_DBG(xe, err)) |
| 806 | goto put_exec_queue; | 1222 | goto delete_queue_group; |
| 807 | } | 1223 | } |
| 808 | 1224 | ||
| 809 | if (q->vm && q->hwe->hw_engine_group) { | 1225 | if (q->vm && q->hwe->hw_engine_group) { |
| @@ -826,6 +1242,9 @@ int xe_exec_queue_create_ioctl(struct drm_device *dev, void *data, · 16 unmodified lines | |||
| 826 | 1242 | ||
| 827 | kill_exec_queue: | 1243 | kill_exec_queue: |
| 828 | xe_exec_queue_kill(q); | 1244 | xe_exec_queue_kill(q); |
| 1245 | delete_queue_group: | ||
| 1246 | if (xe_exec_queue_is_multi_queue_secondary(q)) | ||
| 1247 | xe_exec_queue_group_delete(xe, q); | ||
| 829 | put_exec_queue: | 1248 | put_exec_queue: |
| 830 | xe_exec_queue_put(q); | 1249 | xe_exec_queue_put(q); |
| 831 | return err; | 1250 | return err; |
| @@ -981,6 +1400,11 @@ void xe_exec_queue_kill(struct xe_exec_queue *q) · 149 unmodified lines | |||
| 981 | 1400 | ||
| 982 | q->ops->kill(q); | 1401 | q->ops->kill(q); |
| 983 | xe_vm_remove_compute_exec_queue(q->vm, q); | 1402 | xe_vm_remove_compute_exec_queue(q->vm, q); |
| 1403 | |||
| 1404 | if (!xe_exec_queue_is_multi_queue_primary(q) && q->multi_queue.keep_active) { | ||
| 1405 | xe_exec_queue_group_kill_put(q->multi_queue.group); | ||
| 1406 | q->multi_queue.keep_active = false; | ||
| 1407 | } | ||
| 984 | } | 1408 | } |
| 985 | 1409 | ||
| 986 | int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data, | 1410 | int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data, |
| @@ -1007,7 +1431,10 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data, · 20 unmodified lines | |||
| 1007 | if (q->vm && q->hwe->hw_engine_group) | 1431 | if (q->vm && q->hwe->hw_engine_group) |
| 1008 | xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); | 1432 | xe_hw_engine_group_del_exec_queue(q->hwe->hw_engine_group, q); |
| 1009 | 1433 | ||
| 1010 | xe_exec_queue_kill(q); | 1434 | if (xe_exec_queue_is_multi_queue_primary(q)) |
| 1435 | xe_exec_queue_group_kill_put(q->multi_queue.group); | ||
| 1436 | else | ||
| 1437 | xe_exec_queue_kill(q); | ||
| 1011 | 1438 | ||
| 1012 | trace_xe_exec_queue_close(q); | 1439 | trace_xe_exec_queue_close(q); |
| 1013 | xe_exec_queue_put(q); | 1440 | xe_exec_queue_put(q); |
| @@ -66,6 +66,55 @@ static inline bool xe_exec_queue_uses_pxp(struct xe_exec_queue *q) · 65 unmodified lines | |||
| 66 | return q->pxp.type; | 66 | return q->pxp.type; |
| 67 | } | 67 | } |
| 68 | 68 | ||
| 69 | /** | ||
| 70 | * xe_exec_queue_is_multi_queue() - Whether an exec_queue is part of a queue group. | ||
| 71 | * @q: The exec_queue | ||
| 72 | * | ||
| 73 | * Return: True if the exec_queue is part of a queue group, false otherwise. | ||
| 74 | */ | ||
| 75 | static inline bool xe_exec_queue_is_multi_queue(struct xe_exec_queue *q) | ||
| 76 | { | ||
| 77 | return q->multi_queue.valid; | ||
| 78 | } | ||
| 79 | |||
| 80 | /** | ||
| 81 | * xe_exec_queue_is_multi_queue_primary() - Whether an exec_queue is primary queue | ||
| 82 | * of a multi queue group. | ||
| 83 | * @q: The exec_queue | ||
| 84 | * | ||
| 85 | * Return: True if @q is primary queue of a queue group, false otherwise. | ||
| 86 | */ | ||
| 87 | static inline bool xe_exec_queue_is_multi_queue_primary(struct xe_exec_queue *q) | ||
| 88 | { | ||
| 89 | return q->multi_queue.is_primary; | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * xe_exec_queue_is_multi_queue_secondary() - Whether an exec_queue is secondary queue | ||
| 94 | * of a multi queue group. | ||
| 95 | * @q: The exec_queue | ||
| 96 | * | ||
| 97 | * Return: True if @q is secondary queue of a queue group, false otherwise. | ||
| 98 | */ | ||
| 99 | static inline bool xe_exec_queue_is_multi_queue_secondary(struct xe_exec_queue *q) | ||
| 100 | { | ||
| 101 | return xe_exec_queue_is_multi_queue(q) && !xe_exec_queue_is_multi_queue_primary(q); | ||
| 102 | } | ||
| 103 | |||
| 104 | /** | ||
| 105 | * xe_exec_queue_multi_queue_primary() - Get multi queue group's primary queue | ||
| 106 | * @q: The exec_queue | ||
| 107 | * | ||
| 108 | * If @q belongs to a multi queue group, then the primary queue of the group will | ||
| 109 | * be returned. Otherwise, @q will be returned. | ||
| 110 | */ | ||
| 111 | static inline struct xe_exec_queue *xe_exec_queue_multi_queue_primary(struct xe_exec_queue *q) | ||
| 112 | { | ||
| 113 | return xe_exec_queue_is_multi_queue(q) ? q->multi_queue.group->primary : q; | ||
| 114 | } | ||
| 115 | |||
| 116 | void xe_exec_queue_group_kill_put(struct xe_exec_queue_group *group); | ||
| 117 | |||
| 69 | bool xe_exec_queue_is_lr(struct xe_exec_queue *q); | 118 | bool xe_exec_queue_is_lr(struct xe_exec_queue *q); |
| 70 | 119 | ||
| 71 | bool xe_exec_queue_is_idle(struct xe_exec_queue *q); | 120 | bool xe_exec_queue_is_idle(struct xe_exec_queue *q); |
| @@ -78,6 +127,8 @@ int xe_exec_queue_destroy_ioctl(struct drm_device *dev, void *data, · 6 unmodified lines | |||
| 78 | struct drm_file *file); | 127 | struct drm_file *file); |
| 79 | int xe_exec_queue_get_property_ioctl(struct drm_device *dev, void *data, | 128 | int xe_exec_queue_get_property_ioctl(struct drm_device *dev, void *data, |
| 80 | struct drm_file *file); | 129 | struct drm_file *file); |
| 130 | int xe_exec_queue_set_property_ioctl(struct drm_device *dev, void *data, | ||
| 131 | struct drm_file *file); | ||
| 81 | enum xe_exec_queue_priority xe_exec_queue_device_get_max_priority(struct xe_device *xe); | 132 | enum xe_exec_queue_priority xe_exec_queue_device_get_max_priority(struct xe_device *xe); |
| 82 | 133 | ||
| 83 | void xe_exec_queue_last_fence_put(struct xe_exec_queue *e, struct xe_vm *vm); | 134 | void xe_exec_queue_last_fence_put(struct xe_exec_queue *e, struct xe_vm *vm); |
| @@ -111,4 +162,21 @@ int xe_exec_queue_contexts_hwsp_rebase(struct xe_exec_queue *q, void *scratch); · 27 unmodified lines | |||
| 111 | 162 | ||
| 112 | struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q); | 163 | struct xe_lrc *xe_exec_queue_lrc(struct xe_exec_queue *q); |
| 113 | 164 | ||
| 165 | /** | ||
| 166 | * xe_exec_queue_idle_skip_suspend() - Can exec queue skip suspend | ||
| 167 | * @q: The exec_queue | ||
| 168 | * | ||
| 169 | * If an exec queue is not parallel and is idle, the suspend steps can be | ||
| 170 | * skipped in the submission backend immediatley signaling the suspend fence. | ||
| 171 | * Parallel queues cannot skip this step due to limitations in the submission | ||
| 172 | * backend. | ||
| 173 | * | ||
| 174 | * Return: True if exec queue is idle and can skip suspend steps, False | ||
| 175 | * otherwise | ||
| 176 | */ | ||
| 177 | static inline bool xe_exec_queue_idle_skip_suspend(struct xe_exec_queue *q) | ||
| 178 | { | ||
| 179 | return !xe_exec_queue_is_parallel(q) && xe_exec_queue_is_idle(q); | ||
| 180 | } | ||
| 181 | |||
| 114 | #endif | 182 | #endif |
| @@ -32,6 +32,44 @@ enum xe_exec_queue_priority { · 31 unmodified lines | |||
| 32 | XE_EXEC_QUEUE_PRIORITY_COUNT | 32 | XE_EXEC_QUEUE_PRIORITY_COUNT |
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | /** | ||
| 36 | * enum xe_multi_queue_priority - Multi Queue priority values | ||
| 37 | * | ||
| 38 | * The priority values of the queues within the multi queue group. | ||
| 39 | */ | ||
| 40 | enum xe_multi_queue_priority { | ||
| 41 | /** @XE_MULTI_QUEUE_PRIORITY_LOW: Priority low */ | ||
| 42 | XE_MULTI_QUEUE_PRIORITY_LOW = 0, | ||
| 43 | /** @XE_MULTI_QUEUE_PRIORITY_NORMAL: Priority normal */ | ||
| 44 | XE_MULTI_QUEUE_PRIORITY_NORMAL, | ||
| 45 | /** @XE_MULTI_QUEUE_PRIORITY_HIGH: Priority high */ | ||
| 46 | XE_MULTI_QUEUE_PRIORITY_HIGH, | ||
| 47 | }; | ||
| 48 | |||
| 49 | /** | ||
| 50 | * struct xe_exec_queue_group - Execution multi queue group | ||
| 51 | * | ||
| 52 | * Contains multi queue group information. | ||
| 53 | */ | ||
| 54 | struct xe_exec_queue_group { | ||
| 55 | /** @primary: Primary queue of this group */ | ||
| 56 | struct xe_exec_queue *primary; | ||
| 57 | /** @cgp_bo: BO for the Context Group Page */ | ||
| 58 | struct xe_bo *cgp_bo; | ||
| 59 | /** @xa: xarray to store LRCs */ | ||
| 60 | struct xarray xa; | ||
| 61 | /** @list: List of all secondary queues in the group */ | ||
| 62 | struct list_head list; | ||
| 63 | /** @list_lock: Secondary queue list lock */ | ||
| 64 | struct mutex list_lock; | ||
| 65 | /** @kill_refcount: ref count to kill primary queue */ | ||
| 66 | struct kref kill_refcount; | ||
| 67 | /** @sync_pending: CGP_SYNC_DONE g2h response pending */ | ||
| 68 | bool sync_pending; | ||
| 69 | /** @banned: Group banned */ | ||
| 70 | bool banned; | ||
| 71 | }; | ||
| 72 | |||
| 35 | /** | 73 | /** |
| 36 | * struct xe_exec_queue - Execution queue | 74 | * struct xe_exec_queue - Execution queue |
| 37 | * | 75 | * |
| @@ -111,6 +149,24 @@ struct xe_exec_queue { · 73 unmodified lines | |||
| 111 | struct xe_guc_exec_queue *guc; | 149 | struct xe_guc_exec_queue *guc; |
| 112 | }; | 150 | }; |
| 113 | 151 | ||
| 152 | /** @multi_queue: Multi queue information */ | ||
| 153 | struct { | ||
| 154 | /** @multi_queue.group: Queue group information */ | ||
| 155 | struct xe_exec_queue_group *group; | ||
| 156 | /** @multi_queue.link: Link into group's secondary queues list */ | ||
| 157 | struct list_head link; | ||
| 158 | /** @multi_queue.priority: Queue priority within the multi-queue group */ | ||
| 159 | enum xe_multi_queue_priority priority; | ||
| 160 | /** @multi_queue.pos: Position of queue within the multi-queue group */ | ||
| 161 | u8 pos; | ||
| 162 | /** @multi_queue.valid: Queue belongs to a multi queue group */ | ||
| 163 | u8 valid:1; | ||
| 164 | /** @multi_queue.is_primary: Is primary queue (Q0) of the group */ | ||
| 165 | u8 is_primary:1; | ||
| 166 | /** @multi_queue.keep_active: Keep the group active after primary is destroyed */ | ||
| 167 | u8 keep_active:1; | ||
| 168 | } multi_queue; | ||
| 169 | |||
| 114 | /** @sched_props: scheduling properties */ | 170 | /** @sched_props: scheduling properties */ |
| 115 | struct { | 171 | struct { |
| 116 | /** @sched_props.timeslice_us: timeslice period in micro-seconds */ | 172 | /** @sched_props.timeslice_us: timeslice period in micro-seconds */ |
| @@ -167,6 +223,9 @@ struct xe_exec_queue { · 50 unmodified lines | |||
| 167 | /** @ufence_timeline_value: User fence timeline value */ | 223 | /** @ufence_timeline_value: User fence timeline value */ |
| 168 | u64 ufence_timeline_value; | 224 | u64 ufence_timeline_value; |
| 169 | 225 | ||
| 226 | /** @replay_state: GPU hang replay state */ | ||
| 227 | void *replay_state; | ||
| 228 | |||
| 170 | /** @ops: submission backend exec queue operations */ | 229 | /** @ops: submission backend exec queue operations */ |
| 171 | const struct xe_exec_queue_ops *ops; | 230 | const struct xe_exec_queue_ops *ops; |
| 172 | 231 | ||
| @@ -213,6 +272,9 @@ struct xe_exec_queue_ops { · 40 unmodified lines | |||
| 213 | int (*set_timeslice)(struct xe_exec_queue *q, u32 timeslice_us); | 272 | int (*set_timeslice)(struct xe_exec_queue *q, u32 timeslice_us); |
| 214 | /** @set_preempt_timeout: Set preemption timeout for exec queue */ | 273 | /** @set_preempt_timeout: Set preemption timeout for exec queue */ |
| 215 | int (*set_preempt_timeout)(struct xe_exec_queue *q, u32 preempt_timeout_us); | 274 | int (*set_preempt_timeout)(struct xe_exec_queue *q, u32 preempt_timeout_us); |
| 275 | /** @set_multi_queue_priority: Set multi queue priority */ | ||
| 276 | int (*set_multi_queue_priority)(struct xe_exec_queue *q, | ||
| 277 | enum xe_multi_queue_priority priority); | ||
| 216 | /** | 278 | /** |
| 217 | * @suspend: Suspend exec queue from executing, allowed to be called | 279 | * @suspend: Suspend exec queue from executing, allowed to be called |
| 218 | * multiple times in a row before resume with the caveat that | 280 | * multiple times in a row before resume with the caveat that |
| @@ -269,7 +269,7 @@ struct xe_execlist_port *xe_execlist_port_create(struct xe_device *xe, · 268 unmodified lines | |||
| 269 | 269 | ||
| 270 | port->hwe = hwe; | 270 | port->hwe = hwe; |
| 271 | 271 | ||
| 272 | port->lrc = xe_lrc_create(hwe, NULL, SZ_16K, XE_IRQ_DEFAULT_MSIX, 0); | 272 | port->lrc = xe_lrc_create(hwe, NULL, NULL, SZ_16K, XE_IRQ_DEFAULT_MSIX, 0); |
| 273 | if (IS_ERR(port->lrc)) { | 273 | if (IS_ERR(port->lrc)) { |
| 274 | err = PTR_ERR(port->lrc); | 274 | err = PTR_ERR(port->lrc); |
| 275 | goto err; | 275 | goto err; |
| @@ -166,6 +166,13 @@ static int domain_sleep_wait(struct xe_gt *gt, · 165 unmodified lines | |||
| 166 | * xe_force_wake_ref_has_domain() function. Caller must call | 166 | * xe_force_wake_ref_has_domain() function. Caller must call |
| 167 | * xe_force_wake_put() function to decrease incremented refcounts. | 167 | * xe_force_wake_put() function to decrease incremented refcounts. |
| 168 | * | 168 | * |
| 169 | * When possible, scope-based forcewake (through CLASS(xe_force_wake, ...) or | ||
| 170 | * xe_with_force_wake()) should be used instead of direct calls to this | ||
| 171 | * function. Direct usage of get/put should only be used when the function | ||
| 172 | * has goto-based flows that can interfere with scope-based cleanup, or when | ||
| 173 | * the lifetime of the forcewake reference does not match a specific scope | ||
| 174 | * (e.g., forcewake obtained in one function and released in a different one). | ||
| 175 | * | ||
| 169 | * Return: opaque reference to woken domains or zero if none of requested | 176 | * Return: opaque reference to woken domains or zero if none of requested |
| 170 | * domains were awake. | 177 | * domains were awake. |
| 171 | */ | 178 | */ |
| @@ -61,4 +61,44 @@ xe_force_wake_ref_has_domain(unsigned int fw_ref, enum xe_force_wake_domains dom · 60 unmodified lines | |||
| 61 | return fw_ref & domain; | 61 | return fw_ref & domain; |
| 62 | } | 62 | } |
| 63 | 63 | ||
| 64 | struct xe_force_wake_ref { | ||
| 65 | struct xe_force_wake *fw; | ||
| 66 | unsigned int domains; | ||
| 67 | }; | ||
| 68 | |||
| 69 | static struct xe_force_wake_ref | ||
| 70 | xe_force_wake_constructor(struct xe_force_wake *fw, unsigned int domains) | ||
| 71 | { | ||
| 72 | struct xe_force_wake_ref fw_ref = { .fw = fw }; | ||
| 73 | |||
| 74 | fw_ref.domains = xe_force_wake_get(fw, domains); | ||
| 75 | |||
| 76 | return fw_ref; | ||
| 77 | } | ||
| 78 | |||
| 79 | DEFINE_CLASS(xe_force_wake, struct xe_force_wake_ref, | ||
| 80 | xe_force_wake_put(_T.fw, _T.domains), | ||
| 81 | xe_force_wake_constructor(fw, domains), | ||
| 82 | struct xe_force_wake *fw, unsigned int domains); | ||
| 83 | |||
| 84 | /* | ||
| 85 | * Scoped helper for the forcewake class, using the same trick as scoped_guard() | ||
| 86 | * to bind the lifetime to the next statement/block. | ||
| 87 | */ | ||
| 88 | #define __xe_with_force_wake(ref, fw, domains, done) \ | ||
| 89 | for (CLASS(xe_force_wake, ref)(fw, domains), *(done) = NULL; \ | ||
| 90 | !(done); (done) = (void *)1) | ||
| 91 | |||
| 92 | #define xe_with_force_wake(ref, fw, domains) \ | ||
| 93 | __xe_with_force_wake(ref, fw, domains, __UNIQUE_ID(done)) | ||
| 94 | |||
| 95 | /* | ||
| 96 | * Used when xe_force_wake_constructor() has already been called by another | ||
| 97 | * function and the current function is responsible for releasing the forcewake | ||
| 98 | * reference in all possible cases and error paths. | ||
| 99 | */ | ||
| 100 | DEFINE_CLASS(xe_force_wake_release_only, struct xe_force_wake_ref, | ||
| 101 | if (_T.fw) xe_force_wake_put(_T.fw, _T.domains), fw_ref, | ||
| 102 | struct xe_force_wake_ref fw_ref); | ||
| 103 | |||
| 64 | #endif | 104 | #endif |
| @@ -396,9 +396,8 @@ static void ggtt_node_remove_work_func(struct work_struct *work) · 395 unmodified lines | |||
| 396 | delayed_removal_work); | 396 | delayed_removal_work); |
| 397 | struct xe_device *xe = tile_to_xe(node->ggtt->tile); | 397 | struct xe_device *xe = tile_to_xe(node->ggtt->tile); |
| 398 | 398 | ||
| 399 | xe_pm_runtime_get(xe); | 399 | guard(xe_pm_runtime)(xe); |
| 400 | ggtt_node_remove(node); | 400 | ggtt_node_remove(node); |
| 401 | xe_pm_runtime_put(xe); | ||
| 402 | } | 401 | } |
| 403 | 402 | ||
| 404 | /** | 403 | /** |
| @@ -352,7 +352,6 @@ static void gsc_work(struct work_struct *work) · 351 unmodified lines | |||
| 352 | struct xe_gsc *gsc = container_of(work, typeof(*gsc), work); | 352 | struct xe_gsc *gsc = container_of(work, typeof(*gsc), work); |
| 353 | struct xe_gt *gt = gsc_to_gt(gsc); | 353 | struct xe_gt *gt = gsc_to_gt(gsc); |
| 354 | struct xe_device *xe = gt_to_xe(gt); | 354 | struct xe_device *xe = gt_to_xe(gt); |
| 355 | unsigned int fw_ref; | ||
| 356 | u32 actions; | 355 | u32 actions; |
| 357 | int ret; | 356 | int ret; |
| 358 | 357 | ||
| @@ -361,13 +360,12 @@ static void gsc_work(struct work_struct *work) · 2 unmodified lines | |||
| 361 | gsc->work_actions = 0; | 360 | gsc->work_actions = 0; |
| 362 | spin_unlock_irq(&gsc->lock); | 361 | spin_unlock_irq(&gsc->lock); |
| 363 | 362 | ||
| 364 | xe_pm_runtime_get(xe); | 363 | guard(xe_pm_runtime)(xe); |
| 365 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC); | 364 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC); |
| 366 | 365 | ||
| 367 | if (actions & GSC_ACTION_ER_COMPLETE) { | 366 | if (actions & GSC_ACTION_ER_COMPLETE) { |
| 368 | ret = gsc_er_complete(gt); | 367 | if (gsc_er_complete(gt)) |
| 369 | if (ret) | 368 | return; |
| 370 | goto out; | ||
| 371 | } | 369 | } |
| 372 | 370 | ||
| 373 | if (actions & GSC_ACTION_FW_LOAD) { | 371 | if (actions & GSC_ACTION_FW_LOAD) { |
| @@ -380,10 +378,6 @@ static void gsc_work(struct work_struct *work) · 6 unmodified lines | |||
| 380 | 378 | ||
| 381 | if (actions & GSC_ACTION_SW_PROXY) | 379 | if (actions & GSC_ACTION_SW_PROXY) |
| 382 | xe_gsc_proxy_request_handler(gsc); | 380 | xe_gsc_proxy_request_handler(gsc); |
| 383 | |||
| 384 | out: | ||
| 385 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 386 | xe_pm_runtime_put(xe); | ||
| 387 | } | 381 | } |
| 388 | 382 | ||
| 389 | void xe_gsc_hwe_irq_handler(struct xe_hw_engine *hwe, u16 intr_vec) | 383 | void xe_gsc_hwe_irq_handler(struct xe_hw_engine *hwe, u16 intr_vec) |
| @@ -615,7 +609,6 @@ void xe_gsc_print_info(struct xe_gsc *gsc, struct drm_printer *p) · 225 unmodified lines | |||
| 615 | { | 609 | { |
| 616 | struct xe_gt *gt = gsc_to_gt(gsc); | 610 | struct xe_gt *gt = gsc_to_gt(gsc); |
| 617 | struct xe_mmio *mmio = >->mmio; | 611 | struct xe_mmio *mmio = >->mmio; |
| 618 | unsigned int fw_ref; | ||
| 619 | 612 | ||
| 620 | xe_uc_fw_print(&gsc->fw, p); | 613 | xe_uc_fw_print(&gsc->fw, p); |
| 621 | 614 | ||
| @@ -624,8 +617,8 @@ void xe_gsc_print_info(struct xe_gsc *gsc, struct drm_printer *p) · 2 unmodified lines | |||
| 624 | if (!xe_uc_fw_is_enabled(&gsc->fw)) | 617 | if (!xe_uc_fw_is_enabled(&gsc->fw)) |
| 625 | return; | 618 | return; |
| 626 | 619 | ||
| 627 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC); | 620 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC); |
| 628 | if (!fw_ref) | 621 | if (!fw_ref.domains) |
| 629 | return; | 622 | return; |
| 630 | 623 | ||
| 631 | drm_printf(p, "\nHECI1 FWSTS: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", | 624 | drm_printf(p, "\nHECI1 FWSTS: 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x 0x%08x\n", |
| @@ -635,6 +628,4 @@ void xe_gsc_print_info(struct xe_gsc *gsc, struct drm_printer *p) · 3 unmodified lines | |||
| 635 | xe_mmio_read32(mmio, HECI_FWSTS4(MTL_GSC_HECI1_BASE)), | 628 | xe_mmio_read32(mmio, HECI_FWSTS4(MTL_GSC_HECI1_BASE)), |
| 636 | xe_mmio_read32(mmio, HECI_FWSTS5(MTL_GSC_HECI1_BASE)), | 629 | xe_mmio_read32(mmio, HECI_FWSTS5(MTL_GSC_HECI1_BASE)), |
| 637 | xe_mmio_read32(mmio, HECI_FWSTS6(MTL_GSC_HECI1_BASE))); | 630 | xe_mmio_read32(mmio, HECI_FWSTS6(MTL_GSC_HECI1_BASE))); |
| 638 | |||
| 639 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 640 | } | 631 | } |
| @@ -37,9 +37,8 @@ static int gsc_info(struct seq_file *m, void *data) · 36 unmodified lines | |||
| 37 | struct xe_device *xe = gsc_to_xe(gsc); | 37 | struct xe_device *xe = gsc_to_xe(gsc); |
| 38 | struct drm_printer p = drm_seq_file_printer(m); | 38 | struct drm_printer p = drm_seq_file_printer(m); |
| 39 | 39 | ||
| 40 | xe_pm_runtime_get(xe); | 40 | guard(xe_pm_runtime)(xe); |
| 41 | xe_gsc_print_info(gsc, &p); | 41 | xe_gsc_print_info(gsc, &p); |
| 42 | xe_pm_runtime_put(xe); | ||
| 43 | 42 | ||
| 44 | return 0; | 43 | return 0; |
| 45 | } | 44 | } |
| @@ -440,22 +440,19 @@ static void xe_gsc_proxy_remove(void *arg) · 439 unmodified lines | |||
| 440 | struct xe_gsc *gsc = arg; | 440 | struct xe_gsc *gsc = arg; |
| 441 | struct xe_gt *gt = gsc_to_gt(gsc); | 441 | struct xe_gt *gt = gsc_to_gt(gsc); |
| 442 | struct xe_device *xe = gt_to_xe(gt); | 442 | struct xe_device *xe = gt_to_xe(gt); |
| 443 | unsigned int fw_ref = 0; | ||
| 444 | 443 | ||
| 445 | if (!gsc->proxy.component_added) | 444 | if (!gsc->proxy.component_added) |
| 446 | return; | 445 | return; |
| 447 | 446 | ||
| 448 | /* disable HECI2 IRQs */ | 447 | /* disable HECI2 IRQs */ |
| 449 | xe_pm_runtime_get(xe); | 448 | scoped_guard(xe_pm_runtime, xe) { |
| 450 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC); | 449 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GSC); |
| 451 | if (!fw_ref) | 450 | if (!fw_ref.domains) |
| 452 | xe_gt_err(gt, "failed to get forcewake to disable GSC interrupts\n"); | 451 | xe_gt_err(gt, "failed to get forcewake to disable GSC interrupts\n"); |
| 453 | 452 | ||
| 454 | /* try do disable irq even if forcewake failed */ | 453 | /* try do disable irq even if forcewake failed */ |
| 455 | gsc_proxy_irq_toggle(gsc, false); | 454 | gsc_proxy_irq_toggle(gsc, false); |
| 456 | 455 | } | |
| 457 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 458 | xe_pm_runtime_put(xe); | ||
| 459 | 456 | ||
| 460 | xe_gsc_wait_for_worker_completion(gsc); | 457 | xe_gsc_wait_for_worker_completion(gsc); |
| 461 | 458 | ||
| @@ -103,14 +103,13 @@ void xe_gt_sanitize(struct xe_gt *gt) · 102 unmodified lines | |||
| 103 | 103 | ||
| 104 | static void xe_gt_enable_host_l2_vram(struct xe_gt *gt) | 104 | static void xe_gt_enable_host_l2_vram(struct xe_gt *gt) |
| 105 | { | 105 | { |
| 106 | unsigned int fw_ref; | ||
| 107 | u32 reg; | 106 | u32 reg; |
| 108 | 107 | ||
| 109 | if (!XE_GT_WA(gt, 16023588340)) | 108 | if (!XE_GT_WA(gt, 16023588340)) |
| 110 | return; | 109 | return; |
| 111 | 110 | ||
| 112 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 111 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 113 | if (!fw_ref) | 112 | if (!fw_ref.domains) |
| 114 | return; | 113 | return; |
| 115 | 114 | ||
| 116 | if (xe_gt_is_main_type(gt)) { | 115 | if (xe_gt_is_main_type(gt)) { |
| @@ -120,12 +119,10 @@ static void xe_gt_enable_host_l2_vram(struct xe_gt *gt) · 3 unmodified lines | |||
| 120 | } | 119 | } |
| 121 | 120 | ||
| 122 | xe_gt_mcr_multicast_write(gt, XEHPC_L3CLOS_MASK(3), 0xF); | 121 | xe_gt_mcr_multicast_write(gt, XEHPC_L3CLOS_MASK(3), 0xF); |
| 123 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 124 | } | 122 | } |
| 125 | 123 | ||
| 126 | static void xe_gt_disable_host_l2_vram(struct xe_gt *gt) | 124 | static void xe_gt_disable_host_l2_vram(struct xe_gt *gt) |
| 127 | { | 125 | { |
| 128 | unsigned int fw_ref; | ||
| 129 | u32 reg; | 126 | u32 reg; |
| 130 | 127 | ||
| 131 | if (!XE_GT_WA(gt, 16023588340)) | 128 | if (!XE_GT_WA(gt, 16023588340)) |
| @@ -134,15 +131,13 @@ static void xe_gt_disable_host_l2_vram(struct xe_gt *gt) · 2 unmodified lines | |||
| 134 | if (xe_gt_is_media_type(gt)) | 131 | if (xe_gt_is_media_type(gt)) |
| 135 | return; | 132 | return; |
| 136 | 133 | ||
| 137 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 134 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 138 | if (!fw_ref) | 135 | if (!fw_ref.domains) |
| 139 | return; | 136 | return; |
| 140 | 137 | ||
| 141 | reg = xe_gt_mcr_unicast_read_any(gt, XE2_GAMREQSTRM_CTRL); | 138 | reg = xe_gt_mcr_unicast_read_any(gt, XE2_GAMREQSTRM_CTRL); |
| 142 | reg &= ~CG_DIS_CNTLBUS; | 139 | reg &= ~CG_DIS_CNTLBUS; |
| 143 | xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg); | 140 | xe_gt_mcr_multicast_write(gt, XE2_GAMREQSTRM_CTRL, reg); |
| 144 | |||
| 145 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 146 | } | 141 | } |
| 147 | 142 | ||
| 148 | static void gt_reset_worker(struct work_struct *w); | 143 | static void gt_reset_worker(struct work_struct *w); |
| @@ -389,7 +384,6 @@ put_exec_queue: · 240 unmodified lines | |||
| 389 | 384 | ||
| 390 | int xe_gt_init_early(struct xe_gt *gt) | 385 | int xe_gt_init_early(struct xe_gt *gt) |
| 391 | { | 386 | { |
| 392 | unsigned int fw_ref; | ||
| 393 | int err; | 387 | int err; |
| 394 | 388 | ||
| 395 | if (IS_SRIOV_PF(gt_to_xe(gt))) { | 389 | if (IS_SRIOV_PF(gt_to_xe(gt))) { |
| @@ -436,13 +430,12 @@ int xe_gt_init_early(struct xe_gt *gt) · 40 unmodified lines | |||
| 436 | if (err) | 430 | if (err) |
| 437 | return err; | 431 | return err; |
| 438 | 432 | ||
| 439 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 433 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 440 | if (!fw_ref) | 434 | if (!fw_ref.domains) |
| 441 | return -ETIMEDOUT; | 435 | return -ETIMEDOUT; |
| 442 | 436 | ||
| 443 | xe_gt_mcr_init_early(gt); | 437 | xe_gt_mcr_init_early(gt); |
| 444 | xe_pat_init(gt); | 438 | xe_pat_init(gt); |
| 445 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 446 | 439 | ||
| 447 | return 0; | 440 | return 0; |
| 448 | } | 441 | } |
| @@ -460,16 +453,15 @@ static void dump_pat_on_error(struct xe_gt *gt) · 11 unmodified lines | |||
| 460 | 453 | ||
| 461 | static int gt_init_with_gt_forcewake(struct xe_gt *gt) | 454 | static int gt_init_with_gt_forcewake(struct xe_gt *gt) |
| 462 | { | 455 | { |
| 463 | unsigned int fw_ref; | ||
| 464 | int err; | 456 | int err; |
| 465 | 457 | ||
| 466 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 458 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 467 | if (!fw_ref) | 459 | if (!fw_ref.domains) |
| 468 | return -ETIMEDOUT; | 460 | return -ETIMEDOUT; |
| 469 | 461 | ||
| 470 | err = xe_uc_init(>->uc); | 462 | err = xe_uc_init(>->uc); |
| 471 | if (err) | 463 | if (err) |
| 472 | goto err_force_wake; | 464 | return err; |
| 473 | 465 | ||
| 474 | xe_gt_topology_init(gt); | 466 | xe_gt_topology_init(gt); |
| 475 | xe_gt_mcr_init(gt); | 467 | xe_gt_mcr_init(gt); |
| @@ -478,7 +470,7 @@ static int gt_init_with_gt_forcewake(struct xe_gt *gt) · 2 unmodified lines | |||
| 478 | if (xe_gt_is_main_type(gt)) { | 470 | if (xe_gt_is_main_type(gt)) { |
| 479 | err = xe_ggtt_init(gt_to_tile(gt)->mem.ggtt); | 471 | err = xe_ggtt_init(gt_to_tile(gt)->mem.ggtt); |
| 480 | if (err) | 472 | if (err) |
| 481 | goto err_force_wake; | 473 | return err; |
| 482 | if (IS_SRIOV_PF(gt_to_xe(gt))) | 474 | if (IS_SRIOV_PF(gt_to_xe(gt))) |
| 483 | xe_lmtt_init(>_to_tile(gt)->sriov.pf.lmtt); | 475 | xe_lmtt_init(>_to_tile(gt)->sriov.pf.lmtt); |
| 484 | } | 476 | } |
| @@ -492,17 +484,17 @@ static int gt_init_with_gt_forcewake(struct xe_gt *gt) · 7 unmodified lines | |||
| 492 | err = xe_hw_engines_init_early(gt); | 484 | err = xe_hw_engines_init_early(gt); |
| 493 | if (err) { | 485 | if (err) { |
| 494 | dump_pat_on_error(gt); | 486 | dump_pat_on_error(gt); |
| 495 | goto err_force_wake; | 487 | return err; |
| 496 | } | 488 | } |
| 497 | 489 | ||
| 498 | err = xe_hw_engine_class_sysfs_init(gt); | 490 | err = xe_hw_engine_class_sysfs_init(gt); |
| 499 | if (err) | 491 | if (err) |
| 500 | goto err_force_wake; | 492 | return err; |
| 501 | 493 | ||
| 502 | /* Initialize CCS mode sysfs after early initialization of HW engines */ | 494 | /* Initialize CCS mode sysfs after early initialization of HW engines */ |
| 503 | err = xe_gt_ccs_mode_sysfs_init(gt); | 495 | err = xe_gt_ccs_mode_sysfs_init(gt); |
| 504 | if (err) | 496 | if (err) |
| 505 | goto err_force_wake; | 497 | return err; |
| 506 | 498 | ||
| 507 | /* | 499 | /* |
| 508 | * Stash hardware-reported version. Since this register does not exist | 500 | * Stash hardware-reported version. Since this register does not exist |
| @@ -510,25 +502,16 @@ static int gt_init_with_gt_forcewake(struct xe_gt *gt) · 1 unmodified line | |||
| 510 | */ | 502 | */ |
| 511 | gt->info.gmdid = xe_mmio_read32(>->mmio, GMD_ID); | 503 | gt->info.gmdid = xe_mmio_read32(>->mmio, GMD_ID); |
| 512 | 504 | ||
| 513 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 514 | return 0; | 505 | return 0; |
| 515 | |||
| 516 | err_force_wake: | ||
| 517 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 518 | |||
| 519 | return err; | ||
| 520 | } | 506 | } |
| 521 | 507 | ||
| 522 | static int gt_init_with_all_forcewake(struct xe_gt *gt) | 508 | static int gt_init_with_all_forcewake(struct xe_gt *gt) |
| 523 | { | 509 | { |
| 524 | unsigned int fw_ref; | ||
| 525 | int err; | 510 | int err; |
| 526 | 511 | ||
| 527 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | 512 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 528 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { | 513 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) |
| 529 | err = -ETIMEDOUT; | 514 | return -ETIMEDOUT; |
| 530 | goto err_force_wake; | ||
| 531 | } | ||
| 532 | 515 | ||
| 533 | xe_gt_mcr_set_implicit_defaults(gt); | 516 | xe_gt_mcr_set_implicit_defaults(gt); |
| 534 | xe_wa_process_gt(gt); | 517 | xe_wa_process_gt(gt); |
| @@ -537,20 +520,20 @@ static int gt_init_with_all_forcewake(struct xe_gt *gt) · 2 unmodified lines | |||
| 537 | 520 | ||
| 538 | err = xe_gt_clock_init(gt); | 521 | err = xe_gt_clock_init(gt); |
| 539 | if (err) | 522 | if (err) |
| 540 | goto err_force_wake; | 523 | return err; |
| 541 | 524 | ||
| 542 | xe_mocs_init(gt); | 525 | xe_mocs_init(gt); |
| 543 | err = xe_execlist_init(gt); | 526 | err = xe_execlist_init(gt); |
| 544 | if (err) | 527 | if (err) |
| 545 | goto err_force_wake; | 528 | return err; |
| 546 | 529 | ||
| 547 | err = xe_hw_engines_init(gt); | 530 | err = xe_hw_engines_init(gt); |
| 548 | if (err) | 531 | if (err) |
| 549 | goto err_force_wake; | 532 | return err; |
| 550 | 533 | ||
| 551 | err = xe_uc_init_post_hwconfig(>->uc); | 534 | err = xe_uc_init_post_hwconfig(>->uc); |
| 552 | if (err) | 535 | if (err) |
| 553 | goto err_force_wake; | 536 | return err; |
| 554 | 537 | ||
| 555 | if (xe_gt_is_main_type(gt)) { | 538 | if (xe_gt_is_main_type(gt)) { |
| 556 | /* | 539 | /* |
| @@ -561,10 +544,8 @@ static int gt_init_with_all_forcewake(struct xe_gt *gt) · 4 unmodified lines | |||
| 561 | 544 | ||
| 562 | gt->usm.bb_pool = xe_sa_bo_manager_init(gt_to_tile(gt), | 545 | gt->usm.bb_pool = xe_sa_bo_manager_init(gt_to_tile(gt), |
| 563 | IS_DGFX(xe) ? SZ_1M : SZ_512K, 16); | 546 | IS_DGFX(xe) ? SZ_1M : SZ_512K, 16); |
| 564 | if (IS_ERR(gt->usm.bb_pool)) { | 547 | if (IS_ERR(gt->usm.bb_pool)) |
| 565 | err = PTR_ERR(gt->usm.bb_pool); | 548 | return PTR_ERR(gt->usm.bb_pool); |
| 566 | goto err_force_wake; | ||
| 567 | } | ||
| 568 | } | 549 | } |
| 569 | } | 550 | } |
| 570 | 551 | ||
| @@ -573,12 +554,12 @@ static int gt_init_with_all_forcewake(struct xe_gt *gt) · 2 unmodified lines | |||
| 573 | 554 | ||
| 574 | err = xe_migrate_init(tile->migrate); | 555 | err = xe_migrate_init(tile->migrate); |
| 575 | if (err) | 556 | if (err) |
| 576 | goto err_force_wake; | 557 | return err; |
| 577 | } | 558 | } |
| 578 | 559 | ||
| 579 | err = xe_uc_load_hw(>->uc); | 560 | err = xe_uc_load_hw(>->uc); |
| 580 | if (err) | 561 | if (err) |
| 581 | goto err_force_wake; | 562 | return err; |
| 582 | 563 | ||
| 583 | /* Configure default CCS mode of 1 engine with all resources */ | 564 | /* Configure default CCS mode of 1 engine with all resources */ |
| 584 | if (xe_gt_ccs_mode_enabled(gt)) { | 565 | if (xe_gt_ccs_mode_enabled(gt)) { |
| @@ -592,14 +573,7 @@ static int gt_init_with_all_forcewake(struct xe_gt *gt) · 7 unmodified lines | |||
| 592 | if (IS_SRIOV_PF(gt_to_xe(gt))) | 573 | if (IS_SRIOV_PF(gt_to_xe(gt))) |
| 593 | xe_gt_sriov_pf_init_hw(gt); | 574 | xe_gt_sriov_pf_init_hw(gt); |
| 594 | 575 | ||
| 595 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 596 | |||
| 597 | return 0; | 576 | return 0; |
| 598 | |||
| 599 | err_force_wake: | ||
| 600 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 601 | |||
| 602 | return err; | ||
| 603 | } | 577 | } |
| 604 | 578 | ||
| 605 | static void xe_gt_fini(void *arg) | 579 | static void xe_gt_fini(void *arg) |
| @@ -902,56 +876,42 @@ void xe_gt_reset_async(struct xe_gt *gt) · 296 unmodified lines | |||
| 902 | 876 | ||
| 903 | void xe_gt_suspend_prepare(struct xe_gt *gt) | 877 | void xe_gt_suspend_prepare(struct xe_gt *gt) |
| 904 | { | 878 | { |
| 905 | unsigned int fw_ref; | 879 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 906 | |||
| 907 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | ||
| 908 | |||
| 909 | xe_uc_suspend_prepare(>->uc); | 880 | xe_uc_suspend_prepare(>->uc); |
| 910 | |||
| 911 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 912 | } | 881 | } |
| 913 | 882 | ||
| 914 | int xe_gt_suspend(struct xe_gt *gt) | 883 | int xe_gt_suspend(struct xe_gt *gt) |
| 915 | { | 884 | { |
| 916 | unsigned int fw_ref; | ||
| 917 | int err; | 885 | int err; |
| 918 | 886 | ||
| 919 | xe_gt_dbg(gt, "suspending\n"); | 887 | xe_gt_dbg(gt, "suspending\n"); |
| 920 | xe_gt_sanitize(gt); | 888 | xe_gt_sanitize(gt); |
| 921 | 889 | ||
| 922 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | 890 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 923 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) | 891 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) { |
| 924 | goto err_msg; | 892 | xe_gt_err(gt, "suspend failed (%pe)\n", ERR_PTR(-ETIMEDOUT)); |
| 893 | return -ETIMEDOUT; | ||
| 894 | } | ||
| 925 | 895 | ||
| 926 | err = xe_uc_suspend(>->uc); | 896 | err = xe_uc_suspend(>->uc); |
| 927 | if (err) | 897 | if (err) { |
| 928 | goto err_force_wake; | 898 | xe_gt_err(gt, "suspend failed (%pe)\n", ERR_PTR(err)); |
| 899 | return err; | ||
| 900 | } | ||
| 929 | 901 | ||
| 930 | xe_gt_idle_disable_pg(gt); | 902 | xe_gt_idle_disable_pg(gt); |
| 931 | 903 | ||
| 932 | xe_gt_disable_host_l2_vram(gt); | 904 | xe_gt_disable_host_l2_vram(gt); |
| 933 | 905 | ||
| 934 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 935 | xe_gt_dbg(gt, "suspended\n"); | 906 | xe_gt_dbg(gt, "suspended\n"); |
| 936 | 907 | ||
| 937 | return 0; | 908 | return 0; |
| 938 | |||
| 939 | err_msg: | ||
| 940 | err = -ETIMEDOUT; | ||
| 941 | err_force_wake: | ||
| 942 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 943 | xe_gt_err(gt, "suspend failed (%pe)\n", ERR_PTR(err)); | ||
| 944 | |||
| 945 | return err; | ||
| 946 | } | 909 | } |
| 947 | 910 | ||
| 948 | void xe_gt_shutdown(struct xe_gt *gt) | 911 | void xe_gt_shutdown(struct xe_gt *gt) |
| 949 | { | 912 | { |
| 950 | unsigned int fw_ref; | 913 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 951 | |||
| 952 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | ||
| 953 | do_gt_reset(gt); | 914 | do_gt_reset(gt); |
| 954 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 955 | } | 915 | } |
| 956 | 916 | ||
| 957 | /** | 917 | /** |
| @@ -976,32 +936,72 @@ int xe_gt_sanitize_freq(struct xe_gt *gt) · 18 unmodified lines | |||
| 976 | 936 | ||
| 977 | int xe_gt_resume(struct xe_gt *gt) | 937 | int xe_gt_resume(struct xe_gt *gt) |
| 978 | { | 938 | { |
| 979 | unsigned int fw_ref; | ||
| 980 | int err; | 939 | int err; |
| 981 | 940 | ||
| 982 | xe_gt_dbg(gt, "resuming\n"); | 941 | xe_gt_dbg(gt, "resuming\n"); |
| 983 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | 942 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 984 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) | 943 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) { |
| 985 | goto err_msg; | 944 | xe_gt_err(gt, "resume failed (%pe)\n", ERR_PTR(-ETIMEDOUT)); |
| 945 | return -ETIMEDOUT; | ||
| 946 | } | ||
| 986 | 947 | ||
| 987 | err = do_gt_restart(gt); | 948 | err = do_gt_restart(gt); |
| 988 | if (err) | 949 | if (err) |
| 989 | goto err_force_wake; | 950 | return err; |
| 990 | 951 | ||
| 991 | xe_gt_idle_enable_pg(gt); | 952 | xe_gt_idle_enable_pg(gt); |
| 992 | 953 | ||
| 993 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 994 | xe_gt_dbg(gt, "resumed\n"); | 954 | xe_gt_dbg(gt, "resumed\n"); |
| 995 | 955 | ||
| 996 | return 0; | 956 | return 0; |
| 957 | } | ||
| 997 | 958 | ||
| 998 | err_msg: | 959 | /** |
| 999 | err = -ETIMEDOUT; | 960 | * xe_gt_runtime_suspend() - GT runtime suspend |
| 1000 | err_force_wake: | 961 | * @gt: the GT object |
| 1001 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | 962 | * |
| 1002 | xe_gt_err(gt, "resume failed (%pe)\n", ERR_PTR(err)); | 963 | * Return: 0 on success, negative error code otherwise. |
| 964 | */ | ||
| 965 | int xe_gt_runtime_suspend(struct xe_gt *gt) | ||
| 966 | { | ||
| 967 | xe_gt_dbg(gt, "runtime suspending\n"); | ||
| 1003 | 968 | ||
| 1004 | return err; | 969 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 970 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) { | ||
| 971 | xe_gt_err(gt, "runtime suspend failed (%pe)\n", ERR_PTR(-ETIMEDOUT)); | ||
| 972 | return -ETIMEDOUT; | ||
| 973 | } | ||
| 974 | |||
| 975 | xe_uc_runtime_suspend(>->uc); | ||
| 976 | xe_gt_disable_host_l2_vram(gt); | ||
| 977 | |||
| 978 | xe_gt_dbg(gt, "runtime suspended\n"); | ||
| 979 | |||
| 980 | return 0; | ||
| 981 | } | ||
| 982 | |||
| 983 | /** | ||
| 984 | * xe_gt_runtime_resume() - GT runtime resume | ||
| 985 | * @gt: the GT object | ||
| 986 | * | ||
| 987 | * Return: 0 on success, negative error code otherwise. | ||
| 988 | */ | ||
| 989 | int xe_gt_runtime_resume(struct xe_gt *gt) | ||
| 990 | { | ||
| 991 | xe_gt_dbg(gt, "runtime resuming\n"); | ||
| 992 | |||
| 993 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); | ||
| 994 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) { | ||
| 995 | xe_gt_err(gt, "runtime resume failed (%pe)\n", ERR_PTR(-ETIMEDOUT)); | ||
| 996 | return -ETIMEDOUT; | ||
| 997 | } | ||
| 998 | |||
| 999 | xe_gt_enable_host_l2_vram(gt); | ||
| 1000 | xe_uc_runtime_resume(>->uc); | ||
| 1001 | |||
| 1002 | xe_gt_dbg(gt, "runtime resumed\n"); | ||
| 1003 | |||
| 1004 | return 0; | ||
| 1005 | } | 1005 | } |
| 1006 | 1006 | ||
| 1007 | struct xe_hw_engine *xe_gt_hw_engine(struct xe_gt *gt, | 1007 | struct xe_hw_engine *xe_gt_hw_engine(struct xe_gt *gt, |
| @@ -58,6 +58,8 @@ int xe_gt_suspend(struct xe_gt *gt); · 57 unmodified lines | |||
| 58 | void xe_gt_shutdown(struct xe_gt *gt); | 58 | void xe_gt_shutdown(struct xe_gt *gt); |
| 59 | int xe_gt_resume(struct xe_gt *gt); | 59 | int xe_gt_resume(struct xe_gt *gt); |
| 60 | void xe_gt_reset_async(struct xe_gt *gt); | 60 | void xe_gt_reset_async(struct xe_gt *gt); |
| 61 | int xe_gt_runtime_resume(struct xe_gt *gt); | ||
| 62 | int xe_gt_runtime_suspend(struct xe_gt *gt); | ||
| 61 | void xe_gt_sanitize(struct xe_gt *gt); | 63 | void xe_gt_sanitize(struct xe_gt *gt); |
| 62 | int xe_gt_sanitize_freq(struct xe_gt *gt); | 64 | int xe_gt_sanitize_freq(struct xe_gt *gt); |
| 63 | 65 | ||
| @@ -105,35 +105,24 @@ int xe_gt_debugfs_show_with_rpm(struct seq_file *m, void *data) · 104 unmodified lines | |||
| 105 | struct drm_info_node *node = m->private; | 105 | struct drm_info_node *node = m->private; |
| 106 | struct xe_gt *gt = node_to_gt(node); | 106 | struct xe_gt *gt = node_to_gt(node); |
| 107 | struct xe_device *xe = gt_to_xe(gt); | 107 | struct xe_device *xe = gt_to_xe(gt); |
| 108 | int ret; | ||
| 109 | |||
| 110 | xe_pm_runtime_get(xe); | ||
| 111 | ret = xe_gt_debugfs_simple_show(m, data); | ||
| 112 | xe_pm_runtime_put(xe); | ||
| 113 | 108 | ||
| 114 | return ret; | 109 | guard(xe_pm_runtime)(xe); |
| 110 | return xe_gt_debugfs_simple_show(m, data); | ||
| 115 | } | 111 | } |
| 116 | 112 | ||
| 117 | static int hw_engines(struct xe_gt *gt, struct drm_printer *p) | 113 | static int hw_engines(struct xe_gt *gt, struct drm_printer *p) |
| 118 | { | 114 | { |
| 119 | struct xe_hw_engine *hwe; | 115 | struct xe_hw_engine *hwe; |
| 120 | enum xe_hw_engine_id id; | 116 | enum xe_hw_engine_id id; |
| 121 | unsigned int fw_ref; | ||
| 122 | int ret = 0; | ||
| 123 | 117 | ||
| 124 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | 118 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 125 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { | 119 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) |
| 126 | ret = -ETIMEDOUT; | 120 | return -ETIMEDOUT; |
| 127 | goto fw_put; | ||
| 128 | } | ||
| 129 | 121 | ||
| 130 | for_each_hw_engine(hwe, gt, id) | 122 | for_each_hw_engine(hwe, gt, id) |
| 131 | xe_hw_engine_print(hwe, p); | 123 | xe_hw_engine_print(hwe, p); |
| 132 | 124 | ||
| 133 | fw_put: | 125 | return 0; |
| 134 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 135 | |||
| 136 | return ret; | ||
| 137 | } | 126 | } |
| 138 | 127 | ||
| 139 | static int steering(struct xe_gt *gt, struct drm_printer *p) | 128 | static int steering(struct xe_gt *gt, struct drm_printer *p) |
| @@ -220,6 +209,7 @@ static const struct drm_info_list vf_safe_debugfs_list[] = { · 80 unmodified lines | |||
| 220 | { "default_lrc_vcs", .show = xe_gt_debugfs_show_with_rpm, .data = vcs_default_lrc }, | 209 | { "default_lrc_vcs", .show = xe_gt_debugfs_show_with_rpm, .data = vcs_default_lrc }, |
| 221 | { "default_lrc_vecs", .show = xe_gt_debugfs_show_with_rpm, .data = vecs_default_lrc }, | 210 | { "default_lrc_vecs", .show = xe_gt_debugfs_show_with_rpm, .data = vecs_default_lrc }, |
| 222 | { "hwconfig", .show = xe_gt_debugfs_show_with_rpm, .data = hwconfig }, | 211 | { "hwconfig", .show = xe_gt_debugfs_show_with_rpm, .data = hwconfig }, |
| 212 | { "pat_sw_config", .show = xe_gt_debugfs_simple_show, .data = xe_pat_dump_sw_config }, | ||
| 223 | }; | 213 | }; |
| 224 | 214 | ||
| 225 | /* everything else should be added here */ | 215 | /* everything else should be added here */ |
| @@ -269,9 +259,8 @@ static void force_reset(struct xe_gt *gt) · 43 unmodified lines | |||
| 269 | { | 259 | { |
| 270 | struct xe_device *xe = gt_to_xe(gt); | 260 | struct xe_device *xe = gt_to_xe(gt); |
| 271 | 261 | ||
| 272 | xe_pm_runtime_get(xe); | 262 | guard(xe_pm_runtime)(xe); |
| 273 | xe_gt_reset_async(gt); | 263 | xe_gt_reset_async(gt); |
| 274 | xe_pm_runtime_put(xe); | ||
| 275 | } | 264 | } |
| 276 | 265 | ||
| 277 | static ssize_t force_reset_write(struct file *file, | 266 | static ssize_t force_reset_write(struct file *file, |
| @@ -297,9 +286,8 @@ static void force_reset_sync(struct xe_gt *gt) · 19 unmodified lines | |||
| 297 | { | 286 | { |
| 298 | struct xe_device *xe = gt_to_xe(gt); | 287 | struct xe_device *xe = gt_to_xe(gt); |
| 299 | 288 | ||
| 300 | xe_pm_runtime_get(xe); | 289 | guard(xe_pm_runtime)(xe); |
| 301 | xe_gt_reset(gt); | 290 | xe_gt_reset(gt); |
| 302 | xe_pm_runtime_put(xe); | ||
| 303 | } | 291 | } |
| 304 | 292 | ||
| 305 | static ssize_t force_reset_sync_write(struct file *file, | 293 | static ssize_t force_reset_sync_write(struct file *file, |
| @@ -70,9 +70,8 @@ static ssize_t act_freq_show(struct kobject *kobj, · 69 unmodified lines | |||
| 70 | struct xe_guc_pc *pc = dev_to_pc(dev); | 70 | struct xe_guc_pc *pc = dev_to_pc(dev); |
| 71 | u32 freq; | 71 | u32 freq; |
| 72 | 72 | ||
| 73 | xe_pm_runtime_get(dev_to_xe(dev)); | 73 | guard(xe_pm_runtime)(dev_to_xe(dev)); |
| 74 | freq = xe_guc_pc_get_act_freq(pc); | 74 | freq = xe_guc_pc_get_act_freq(pc); |
| 75 | xe_pm_runtime_put(dev_to_xe(dev)); | ||
| 76 | 75 | ||
| 77 | return sysfs_emit(buf, "%d\n", freq); | 76 | return sysfs_emit(buf, "%d\n", freq); |
| 78 | } | 77 | } |
| @@ -86,9 +85,8 @@ static ssize_t cur_freq_show(struct kobject *kobj, · 7 unmodified lines | |||
| 86 | u32 freq; | 85 | u32 freq; |
| 87 | ssize_t ret; | 86 | ssize_t ret; |
| 88 | 87 | ||
| 89 | xe_pm_runtime_get(dev_to_xe(dev)); | 88 | guard(xe_pm_runtime)(dev_to_xe(dev)); |
| 90 | ret = xe_guc_pc_get_cur_freq(pc, &freq); | 89 | ret = xe_guc_pc_get_cur_freq(pc, &freq); |
| 91 | xe_pm_runtime_put(dev_to_xe(dev)); | ||
| 92 | if (ret) | 90 | if (ret) |
| 93 | return ret; | 91 | return ret; |
| 94 | 92 | ||
| @@ -113,9 +111,8 @@ static ssize_t rpe_freq_show(struct kobject *kobj, · 18 unmodified lines | |||
| 113 | struct xe_guc_pc *pc = dev_to_pc(dev); | 111 | struct xe_guc_pc *pc = dev_to_pc(dev); |
| 114 | u32 freq; | 112 | u32 freq; |
| 115 | 113 | ||
| 116 | xe_pm_runtime_get(dev_to_xe(dev)); | 114 | guard(xe_pm_runtime)(dev_to_xe(dev)); |
| 117 | freq = xe_guc_pc_get_rpe_freq(pc); | 115 | freq = xe_guc_pc_get_rpe_freq(pc); |
| 118 | xe_pm_runtime_put(dev_to_xe(dev)); | ||
| 119 | 116 | ||
| 120 | return sysfs_emit(buf, "%d\n", freq); | 117 | return sysfs_emit(buf, "%d\n", freq); |
| 121 | } | 118 | } |
| @@ -128,9 +125,8 @@ static ssize_t rpa_freq_show(struct kobject *kobj, · 6 unmodified lines | |||
| 128 | struct xe_guc_pc *pc = dev_to_pc(dev); | 125 | struct xe_guc_pc *pc = dev_to_pc(dev); |
| 129 | u32 freq; | 126 | u32 freq; |
| 130 | 127 | ||
| 131 | xe_pm_runtime_get(dev_to_xe(dev)); | 128 | guard(xe_pm_runtime)(dev_to_xe(dev)); |
| 132 | freq = xe_guc_pc_get_rpa_freq(pc); | 129 | freq = xe_guc_pc_get_rpa_freq(pc); |
| 133 | xe_pm_runtime_put(dev_to_xe(dev)); | ||
| 134 | 130 | ||
| 135 | return sysfs_emit(buf, "%d\n", freq); | 131 | return sysfs_emit(buf, "%d\n", freq); |
| 136 | } | 132 | } |
| @@ -154,9 +150,8 @@ static ssize_t min_freq_show(struct kobject *kobj, · 17 unmodified lines | |||
| 154 | u32 freq; | 150 | u32 freq; |
| 155 | ssize_t ret; | 151 | ssize_t ret; |
| 156 | 152 | ||
| 157 | xe_pm_runtime_get(dev_to_xe(dev)); | 153 | guard(xe_pm_runtime)(dev_to_xe(dev)); |
| 158 | ret = xe_guc_pc_get_min_freq(pc, &freq); | 154 | ret = xe_guc_pc_get_min_freq(pc, &freq); |
| 159 | xe_pm_runtime_put(dev_to_xe(dev)); | ||
| 160 | if (ret) | 155 | if (ret) |
| 161 | return ret; | 156 | return ret; |
| 162 | 157 | ||
| @@ -175,9 +170,8 @@ static ssize_t min_freq_store(struct kobject *kobj, · 12 unmodified lines | |||
| 175 | if (ret) | 170 | if (ret) |
| 176 | return ret; | 171 | return ret; |
| 177 | 172 | ||
| 178 | xe_pm_runtime_get(dev_to_xe(dev)); | 173 | guard(xe_pm_runtime)(dev_to_xe(dev)); |
| 179 | ret = xe_guc_pc_set_min_freq(pc, freq); | 174 | ret = xe_guc_pc_set_min_freq(pc, freq); |
| 180 | xe_pm_runtime_put(dev_to_xe(dev)); | ||
| 181 | if (ret) | 175 | if (ret) |
| 182 | return ret; | 176 | return ret; |
| 183 | 177 | ||
| @@ -193,9 +187,8 @@ static ssize_t max_freq_show(struct kobject *kobj, · 9 unmodified lines | |||
| 193 | u32 freq; | 187 | u32 freq; |
| 194 | ssize_t ret; | 188 | ssize_t ret; |
| 195 | 189 | ||
| 196 | xe_pm_runtime_get(dev_to_xe(dev)); | 190 | guard(xe_pm_runtime)(dev_to_xe(dev)); |
| 197 | ret = xe_guc_pc_get_max_freq(pc, &freq); | 191 | ret = xe_guc_pc_get_max_freq(pc, &freq); |
| 198 | xe_pm_runtime_put(dev_to_xe(dev)); | ||
| 199 | if (ret) | 192 | if (ret) |
| 200 | return ret; | 193 | return ret; |
| 201 | 194 | ||
| @@ -214,9 +207,8 @@ static ssize_t max_freq_store(struct kobject *kobj, · 12 unmodified lines | |||
| 214 | if (ret) | 207 | if (ret) |
| 215 | return ret; | 208 | return ret; |
| 216 | 209 | ||
| 217 | xe_pm_runtime_get(dev_to_xe(dev)); | 210 | guard(xe_pm_runtime)(dev_to_xe(dev)); |
| 218 | ret = xe_guc_pc_set_max_freq(pc, freq); | 211 | ret = xe_guc_pc_set_max_freq(pc, freq); |
| 219 | xe_pm_runtime_put(dev_to_xe(dev)); | ||
| 220 | if (ret) | 212 | if (ret) |
| 221 | return ret; | 213 | return ret; |
| 222 | 214 | ||
| @@ -243,9 +235,8 @@ static ssize_t power_profile_store(struct kobject *kobj, · 20 unmodified lines | |||
| 243 | struct xe_guc_pc *pc = dev_to_pc(dev); | 235 | struct xe_guc_pc *pc = dev_to_pc(dev); |
| 244 | int err; | 236 | int err; |
| 245 | 237 | ||
| 246 | xe_pm_runtime_get(dev_to_xe(dev)); | 238 | guard(xe_pm_runtime)(dev_to_xe(dev)); |
| 247 | err = xe_guc_pc_set_power_profile(pc, buff); | 239 | err = xe_guc_pc_set_power_profile(pc, buff); |
| 248 | xe_pm_runtime_put(dev_to_xe(dev)); | ||
| 249 | 240 | ||
| 250 | return err ?: count; | 241 | return err ?: count; |
| 251 | } | 242 | } |
| @@ -105,7 +105,6 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt) · 104 unmodified lines | |||
| 105 | struct xe_gt_idle *gtidle = >->gtidle; | 105 | struct xe_gt_idle *gtidle = >->gtidle; |
| 106 | struct xe_mmio *mmio = >->mmio; | 106 | struct xe_mmio *mmio = >->mmio; |
| 107 | u32 vcs_mask, vecs_mask; | 107 | u32 vcs_mask, vecs_mask; |
| 108 | unsigned int fw_ref; | ||
| 109 | int i, j; | 108 | int i, j; |
| 110 | 109 | ||
| 111 | if (IS_SRIOV_VF(xe)) | 110 | if (IS_SRIOV_VF(xe)) |
| @@ -137,7 +136,7 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt) · 25 unmodified lines | |||
| 137 | } | 136 | } |
| 138 | } | 137 | } |
| 139 | 138 | ||
| 140 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 139 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 141 | if (xe->info.skip_guc_pc) { | 140 | if (xe->info.skip_guc_pc) { |
| 142 | /* | 141 | /* |
| 143 | * GuC sets the hysteresis value when GuC PC is enabled | 142 | * GuC sets the hysteresis value when GuC PC is enabled |
| @@ -154,13 +153,11 @@ void xe_gt_idle_enable_pg(struct xe_gt *gt) · 10 unmodified lines | |||
| 154 | VDN_MFXVDENC_POWERGATE_ENABLE(2)); | 153 | VDN_MFXVDENC_POWERGATE_ENABLE(2)); |
| 155 | 154 | ||
| 156 | xe_mmio_write32(mmio, POWERGATE_ENABLE, gtidle->powergate_enable); | 155 | xe_mmio_write32(mmio, POWERGATE_ENABLE, gtidle->powergate_enable); |
| 157 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 158 | } | 156 | } |
| 159 | 157 | ||
| 160 | void xe_gt_idle_disable_pg(struct xe_gt *gt) | 158 | void xe_gt_idle_disable_pg(struct xe_gt *gt) |
| 161 | { | 159 | { |
| 162 | struct xe_gt_idle *gtidle = >->gtidle; | 160 | struct xe_gt_idle *gtidle = >->gtidle; |
| 163 | unsigned int fw_ref; | ||
| 164 | 161 | ||
| 165 | if (IS_SRIOV_VF(gt_to_xe(gt))) | 162 | if (IS_SRIOV_VF(gt_to_xe(gt))) |
| 166 | return; | 163 | return; |
| @@ -168,9 +165,8 @@ void xe_gt_idle_disable_pg(struct xe_gt *gt) · 1 unmodified line | |||
| 168 | xe_device_assert_mem_access(gt_to_xe(gt)); | 165 | xe_device_assert_mem_access(gt_to_xe(gt)); |
| 169 | gtidle->powergate_enable = 0; | 166 | gtidle->powergate_enable = 0; |
| 170 | 167 | ||
| 171 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 168 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 172 | xe_mmio_write32(>->mmio, POWERGATE_ENABLE, gtidle->powergate_enable); | 169 | xe_mmio_write32(>->mmio, POWERGATE_ENABLE, gtidle->powergate_enable); |
| 173 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 174 | } | 170 | } |
| 175 | 171 | ||
| 176 | /** | 172 | /** |
| @@ -189,7 +185,6 @@ int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p) · 12 unmodified lines | |||
| 189 | enum xe_gt_idle_state state; | 185 | enum xe_gt_idle_state state; |
| 190 | u32 pg_enabled, pg_status = 0; | 186 | u32 pg_enabled, pg_status = 0; |
| 191 | u32 vcs_mask, vecs_mask; | 187 | u32 vcs_mask, vecs_mask; |
| 192 | unsigned int fw_ref; | ||
| 193 | int n; | 188 | int n; |
| 194 | /* | 189 | /* |
| 195 | * Media Slices | 190 | * Media Slices |
| @@ -226,14 +221,12 @@ int xe_gt_idle_pg_print(struct xe_gt *gt, struct drm_printer *p) · 30 unmodified lines | |||
| 226 | 221 | ||
| 227 | /* Do not wake the GT to read powergating status */ | 222 | /* Do not wake the GT to read powergating status */ |
| 228 | if (state != GT_IDLE_C6) { | 223 | if (state != GT_IDLE_C6) { |
| 229 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 224 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 230 | if (!fw_ref) | 225 | if (!fw_ref.domains) |
| 231 | return -ETIMEDOUT; | 226 | return -ETIMEDOUT; |
| 232 | 227 | ||
| 233 | pg_enabled = xe_mmio_read32(>->mmio, POWERGATE_ENABLE); | 228 | pg_enabled = xe_mmio_read32(>->mmio, POWERGATE_ENABLE); |
| 234 | pg_status = xe_mmio_read32(>->mmio, POWERGATE_DOMAIN_STATUS); | 229 | pg_status = xe_mmio_read32(>->mmio, POWERGATE_DOMAIN_STATUS); |
| 235 | |||
| 236 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 237 | } | 230 | } |
| 238 | 231 | ||
| 239 | if (gt->info.engine_mask & XE_HW_ENGINE_RCS_MASK) { | 232 | if (gt->info.engine_mask & XE_HW_ENGINE_RCS_MASK) { |
| @@ -271,13 +264,9 @@ static ssize_t name_show(struct kobject *kobj, · 31 unmodified lines | |||
| 271 | struct device *dev = kobj_to_dev(kobj); | 264 | struct device *dev = kobj_to_dev(kobj); |
| 272 | struct xe_gt_idle *gtidle = dev_to_gtidle(dev); | 265 | struct xe_gt_idle *gtidle = dev_to_gtidle(dev); |
| 273 | struct xe_guc_pc *pc = gtidle_to_pc(gtidle); | 266 | struct xe_guc_pc *pc = gtidle_to_pc(gtidle); |
| 274 | ssize_t ret; | ||
| 275 | |||
| 276 | xe_pm_runtime_get(pc_to_xe(pc)); | ||
| 277 | ret = sysfs_emit(buff, "%s\n", gtidle->name); | ||
| 278 | xe_pm_runtime_put(pc_to_xe(pc)); | ||
| 279 | 267 | ||
| 280 | return ret; | 268 | guard(xe_pm_runtime)(pc_to_xe(pc)); |
| 269 | return sysfs_emit(buff, "%s\n", gtidle->name); | ||
| 281 | } | 270 | } |
| 282 | static struct kobj_attribute name_attr = __ATTR_RO(name); | 271 | static struct kobj_attribute name_attr = __ATTR_RO(name); |
| 283 | 272 | ||
| @@ -289,9 +278,8 @@ static ssize_t idle_status_show(struct kobject *kobj, · 5 unmodified lines | |||
| 289 | struct xe_guc_pc *pc = gtidle_to_pc(gtidle); | 278 | struct xe_guc_pc *pc = gtidle_to_pc(gtidle); |
| 290 | enum xe_gt_idle_state state; | 279 | enum xe_gt_idle_state state; |
| 291 | 280 | ||
| 292 | xe_pm_runtime_get(pc_to_xe(pc)); | 281 | scoped_guard(xe_pm_runtime, pc_to_xe(pc)) |
| 293 | state = gtidle->idle_status(pc); | 282 | state = gtidle->idle_status(pc); |
| 294 | xe_pm_runtime_put(pc_to_xe(pc)); | ||
| 295 | 283 | ||
| 296 | return sysfs_emit(buff, "%s\n", gt_idle_state_to_string(state)); | 284 | return sysfs_emit(buff, "%s\n", gt_idle_state_to_string(state)); |
| 297 | } | 285 | } |
| @@ -319,9 +307,8 @@ static ssize_t idle_residency_ms_show(struct kobject *kobj, · 21 unmodified lines | |||
| 319 | struct xe_guc_pc *pc = gtidle_to_pc(gtidle); | 307 | struct xe_guc_pc *pc = gtidle_to_pc(gtidle); |
| 320 | u64 residency; | 308 | u64 residency; |
| 321 | 309 | ||
| 322 | xe_pm_runtime_get(pc_to_xe(pc)); | 310 | scoped_guard(xe_pm_runtime, pc_to_xe(pc)) |
| 323 | residency = xe_gt_idle_residency_msec(gtidle); | 311 | residency = xe_gt_idle_residency_msec(gtidle); |
| 324 | xe_pm_runtime_put(pc_to_xe(pc)); | ||
| 325 | 312 | ||
| 326 | return sysfs_emit(buff, "%llu\n", residency); | 313 | return sysfs_emit(buff, "%llu\n", residency); |
| 327 | } | 314 | } |
| @@ -404,21 +391,17 @@ void xe_gt_idle_enable_c6(struct xe_gt *gt) · 76 unmodified lines | |||
| 404 | 391 | ||
| 405 | int xe_gt_idle_disable_c6(struct xe_gt *gt) | 392 | int xe_gt_idle_disable_c6(struct xe_gt *gt) |
| 406 | { | 393 | { |
| 407 | unsigned int fw_ref; | ||
| 408 | |||
| 409 | xe_device_assert_mem_access(gt_to_xe(gt)); | 394 | xe_device_assert_mem_access(gt_to_xe(gt)); |
| 410 | 395 | ||
| 411 | if (IS_SRIOV_VF(gt_to_xe(gt))) | 396 | if (IS_SRIOV_VF(gt_to_xe(gt))) |
| 412 | return 0; | 397 | return 0; |
| 413 | 398 | ||
| 414 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 399 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 415 | if (!fw_ref) | 400 | if (!fw_ref.domains) |
| 416 | return -ETIMEDOUT; | 401 | return -ETIMEDOUT; |
| 417 | 402 | ||
| 418 | xe_mmio_write32(>->mmio, RC_CONTROL, 0); | 403 | xe_mmio_write32(>->mmio, RC_CONTROL, 0); |
| 419 | xe_mmio_write32(>->mmio, RC_STATE, 0); | 404 | xe_mmio_write32(>->mmio, RC_STATE, 0); |
| 420 | 405 | ||
| 421 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 422 | |||
| 423 | return 0; | 406 | return 0; |
| 424 | } | 407 | } |
| @@ -269,7 +269,8 @@ static u32 encode_config_ggtt(u32 *cfg, const struct xe_gt_sriov_config *config, · 268 unmodified lines | |||
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | /* Return: number of configuration dwords written */ | 271 | /* Return: number of configuration dwords written */ |
| 272 | static u32 encode_config(u32 *cfg, const struct xe_gt_sriov_config *config, bool details) | 272 | static u32 encode_config(struct xe_gt *gt, u32 *cfg, const struct xe_gt_sriov_config *config, |
| 273 | bool details) | ||
| 273 | { | 274 | { |
| 274 | u32 n = 0; | 275 | u32 n = 0; |
| 275 | 276 | ||
| @@ -303,9 +304,11 @@ static u32 encode_config(u32 *cfg, const struct xe_gt_sriov_config *config, bool · 27 unmodified lines | |||
| 303 | cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_PREEMPT_TIMEOUT); | 304 | cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_PREEMPT_TIMEOUT); |
| 304 | cfg[n++] = config->preempt_timeout; | 305 | cfg[n++] = config->preempt_timeout; |
| 305 | 306 | ||
| 306 | #define encode_threshold_config(TAG, ...) ({ \ | 307 | #define encode_threshold_config(TAG, NAME, VER...) ({ \ |
| 307 | cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_THRESHOLD_##TAG); \ | 308 | if (IF_ARGS(GUC_FIRMWARE_VER_AT_LEAST(>->uc.guc, VER), true, VER)) { \ |
| 308 | cfg[n++] = config->thresholds[MAKE_XE_GUC_KLV_THRESHOLD_INDEX(TAG)]; \ | 309 | cfg[n++] = PREP_GUC_KLV_TAG(VF_CFG_THRESHOLD_##TAG); \ |
| 310 | cfg[n++] = config->thresholds[MAKE_XE_GUC_KLV_THRESHOLD_INDEX(TAG)]; \ | ||
| 311 | } \ | ||
| 309 | }); | 312 | }); |
| 310 | 313 | ||
| 311 | MAKE_XE_GUC_KLV_THRESHOLDS_SET(encode_threshold_config); | 314 | MAKE_XE_GUC_KLV_THRESHOLDS_SET(encode_threshold_config); |
| @@ -328,7 +331,7 @@ static int pf_push_full_vf_config(struct xe_gt *gt, unsigned int vfid) · 16 unmodified lines | |||
| 328 | return -ENOBUFS; | 331 | return -ENOBUFS; |
| 329 | 332 | ||
| 330 | cfg = xe_guc_buf_cpu_ptr(buf); | 333 | cfg = xe_guc_buf_cpu_ptr(buf); |
| 331 | num_dwords = encode_config(cfg, config, true); | 334 | num_dwords = encode_config(gt, cfg, config, true); |
| 332 | xe_gt_assert(gt, num_dwords <= max_cfg_dwords); | 335 | xe_gt_assert(gt, num_dwords <= max_cfg_dwords); |
| 333 | 336 | ||
| 334 | if (xe_gt_is_media_type(gt)) { | 337 | if (xe_gt_is_media_type(gt)) { |
| @@ -2518,7 +2521,7 @@ ssize_t xe_gt_sriov_pf_config_save(struct xe_gt *gt, unsigned int vfid, void *bu · 2183 unmodified lines | |||
| 2518 | ret = -ENOBUFS; | 2521 | ret = -ENOBUFS; |
| 2519 | } else { | 2522 | } else { |
| 2520 | config = pf_pick_vf_config(gt, vfid); | 2523 | config = pf_pick_vf_config(gt, vfid); |
| 2521 | ret = encode_config(buf, config, false) * sizeof(u32); | 2524 | ret = encode_config(gt, buf, config, false) * sizeof(u32); |
| 2522 | } | 2525 | } |
| 2523 | } | 2526 | } |
| 2524 | mutex_unlock(xe_gt_sriov_pf_master_mutex(gt)); | 2527 | mutex_unlock(xe_gt_sriov_pf_master_mutex(gt)); |
| @@ -2551,11 +2554,13 @@ static int pf_restore_vf_config_klv(struct xe_gt *gt, unsigned int vfid, · 26 unmodified lines | |||
| 2551 | return pf_provision_preempt_timeout(gt, vfid, value[0]); | 2554 | return pf_provision_preempt_timeout(gt, vfid, value[0]); |
| 2552 | 2555 | ||
| 2553 | /* auto-generate case statements */ | 2556 | /* auto-generate case statements */ |
| 2554 | #define define_threshold_key_to_provision_case(TAG, ...) \ | 2557 | #define define_threshold_key_to_provision_case(TAG, NAME, VER...) \ |
| 2555 | case MAKE_GUC_KLV_VF_CFG_THRESHOLD_KEY(TAG): \ | 2558 | case MAKE_GUC_KLV_VF_CFG_THRESHOLD_KEY(TAG): \ |
| 2556 | BUILD_BUG_ON(MAKE_GUC_KLV_VF_CFG_THRESHOLD_LEN(TAG) != 1u); \ | 2559 | BUILD_BUG_ON(MAKE_GUC_KLV_VF_CFG_THRESHOLD_LEN(TAG) != 1u); \ |
| 2557 | if (len != MAKE_GUC_KLV_VF_CFG_THRESHOLD_LEN(TAG)) \ | 2560 | if (len != MAKE_GUC_KLV_VF_CFG_THRESHOLD_LEN(TAG)) \ |
| 2558 | return -EBADMSG; \ | 2561 | return -EBADMSG; \ |
| 2562 | if (IF_ARGS(!GUC_FIRMWARE_VER_AT_LEAST(>->uc.guc, VER), false, VER)) \ | ||
| 2563 | return -EKEYREJECTED; \ | ||
| 2559 | return pf_provision_threshold(gt, vfid, \ | 2564 | return pf_provision_threshold(gt, vfid, \ |
| 2560 | MAKE_XE_GUC_KLV_THRESHOLD_INDEX(TAG), \ | 2565 | MAKE_XE_GUC_KLV_THRESHOLD_INDEX(TAG), \ |
| 2561 | value[0]); | 2566 | value[0]); |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include "xe_gt_sriov_pf_monitor.h" | 21 | #include "xe_gt_sriov_pf_monitor.h" |
| 22 | #include "xe_gt_sriov_pf_policy.h" | 22 | #include "xe_gt_sriov_pf_policy.h" |
| 23 | #include "xe_gt_sriov_pf_service.h" | 23 | #include "xe_gt_sriov_pf_service.h" |
| 24 | #include "xe_guc.h" | ||
| 24 | #include "xe_pm.h" | 25 | #include "xe_pm.h" |
| 25 | #include "xe_sriov_pf.h" | 26 | #include "xe_sriov_pf.h" |
| 26 | #include "xe_sriov_pf_provision.h" | 27 | #include "xe_sriov_pf_provision.h" |
| @@ -123,11 +124,10 @@ static int POLICY##_set(void *data, u64 val) \ · 96 unmodified lines | |||
| 123 | if (val > (TYPE)~0ull) \ | 124 | if (val > (TYPE)~0ull) \ |
| 124 | return -EOVERFLOW; \ | 125 | return -EOVERFLOW; \ |
| 125 | \ | 126 | \ |
| 126 | xe_pm_runtime_get(xe); \ | 127 | guard(xe_pm_runtime)(xe); \ |
| 127 | err = xe_gt_sriov_pf_policy_set_##POLICY(gt, val); \ | 128 | err = xe_gt_sriov_pf_policy_set_##POLICY(gt, val); \ |
| 128 | if (!err) \ | 129 | if (!err) \ |
| 129 | xe_sriov_pf_provision_set_custom_mode(xe); \ | 130 | xe_sriov_pf_provision_set_custom_mode(xe); \ |
| 130 | xe_pm_runtime_put(xe); \ | ||
| 131 | \ | 131 | \ |
| 132 | return err; \ | 132 | return err; \ |
| 133 | } \ | 133 | } \ |
| @@ -189,12 +189,11 @@ static int CONFIG##_set(void *data, u64 val) \ · 55 unmodified lines | |||
| 189 | if (val > (TYPE)~0ull) \ | 189 | if (val > (TYPE)~0ull) \ |
| 190 | return -EOVERFLOW; \ | 190 | return -EOVERFLOW; \ |
| 191 | \ | 191 | \ |
| 192 | xe_pm_runtime_get(xe); \ | 192 | guard(xe_pm_runtime)(xe); \ |
| 193 | err = xe_sriov_pf_wait_ready(xe) ?: \ | 193 | err = xe_sriov_pf_wait_ready(xe) ?: \ |
| 194 | xe_gt_sriov_pf_config_set_##CONFIG(gt, vfid, val); \ | 194 | xe_gt_sriov_pf_config_set_##CONFIG(gt, vfid, val); \ |
| 195 | if (!err) \ | 195 | if (!err) \ |
| 196 | xe_sriov_pf_provision_set_custom_mode(xe); \ | 196 | xe_sriov_pf_provision_set_custom_mode(xe); \ |
| 197 | xe_pm_runtime_put(xe); \ | ||
| 198 | \ | 197 | \ |
| 199 | return err; \ | 198 | return err; \ |
| 200 | } \ | 199 | } \ |
| @@ -249,11 +248,10 @@ static int set_threshold(void *data, u64 val, enum xe_guc_klv_threshold_index in · 48 unmodified lines | |||
| 249 | if (val > (u32)~0ull) | 248 | if (val > (u32)~0ull) |
| 250 | return -EOVERFLOW; | 249 | return -EOVERFLOW; |
| 251 | 250 | ||
| 252 | xe_pm_runtime_get(xe); | 251 | guard(xe_pm_runtime)(xe); |
| 253 | err = xe_gt_sriov_pf_config_set_threshold(gt, vfid, index, val); | 252 | err = xe_gt_sriov_pf_config_set_threshold(gt, vfid, index, val); |
| 254 | if (!err) | 253 | if (!err) |
| 255 | xe_sriov_pf_provision_set_custom_mode(xe); | 254 | xe_sriov_pf_provision_set_custom_mode(xe); |
| 256 | xe_pm_runtime_put(xe); | ||
| 257 | 255 | ||
| 258 | return err; | 256 | return err; |
| 259 | } | 257 | } |
| @@ -304,9 +302,11 @@ static void pf_add_config_attrs(struct xe_gt *gt, struct dentry *parent, unsigne · 44 unmodified lines | |||
| 304 | &sched_priority_fops); | 302 | &sched_priority_fops); |
| 305 | 303 | ||
| 306 | /* register all threshold attributes */ | 304 | /* register all threshold attributes */ |
| 307 | #define register_threshold_attribute(TAG, NAME, ...) \ | 305 | #define register_threshold_attribute(TAG, NAME, VER...) ({ \ |
| 308 | debugfs_create_file_unsafe("threshold_" #NAME, 0644, parent, parent, \ | 306 | if (IF_ARGS(GUC_FIRMWARE_VER_AT_LEAST(>->uc.guc, VER), true, VER)) \ |
| 309 | &NAME##_fops); | 307 | debugfs_create_file_unsafe("threshold_" #NAME, 0644, parent, parent, \ |
| 308 | &NAME##_fops); \ | ||
| 309 | }); | ||
| 310 | MAKE_XE_GUC_KLV_THRESHOLDS_SET(register_threshold_attribute) | 310 | MAKE_XE_GUC_KLV_THRESHOLDS_SET(register_threshold_attribute) |
| 311 | #undef register_threshold_attribute | 311 | #undef register_threshold_attribute |
| 312 | } | 312 | } |
| @@ -358,9 +358,8 @@ static ssize_t control_write(struct file *file, const char __user *buf, size_t c · 45 unmodified lines | |||
| 358 | xe_gt_assert(gt, sizeof(cmd) > strlen(control_cmds[n].cmd)); | 358 | xe_gt_assert(gt, sizeof(cmd) > strlen(control_cmds[n].cmd)); |
| 359 | 359 | ||
| 360 | if (sysfs_streq(cmd, control_cmds[n].cmd)) { | 360 | if (sysfs_streq(cmd, control_cmds[n].cmd)) { |
| 361 | xe_pm_runtime_get(xe); | 361 | guard(xe_pm_runtime)(xe); |
| 362 | ret = control_cmds[n].fn ? (*control_cmds[n].fn)(gt, vfid) : 0; | 362 | ret = control_cmds[n].fn ? (*control_cmds[n].fn)(gt, vfid) : 0; |
| 363 | xe_pm_runtime_put(xe); | ||
| 364 | break; | 363 | break; |
| 365 | } | 364 | } |
| 366 | } | 365 | } |
| @@ -1026,7 +1026,7 @@ static void action_ring_cleanup(void *arg) · 1025 unmodified lines | |||
| 1026 | 1026 | ||
| 1027 | static void pf_gt_migration_check_support(struct xe_gt *gt) | 1027 | static void pf_gt_migration_check_support(struct xe_gt *gt) |
| 1028 | { | 1028 | { |
| 1029 | if (GUC_FIRMWARE_VER(>->uc.guc) < MAKE_GUC_VER(70, 54, 0)) | 1029 | if (!GUC_FIRMWARE_VER_AT_LEAST(>->uc.guc, 70, 54)) |
| 1030 | xe_sriov_pf_migration_disable(gt_to_xe(gt), "requires GuC version >= 70.54.0"); | 1030 | xe_sriov_pf_migration_disable(gt_to_xe(gt), "requires GuC version >= 70.54.0"); |
| 1031 | } | 1031 | } |
| 1032 | 1032 | ||
| @@ -5,6 +5,7 @@ · 4 unmodified lines | |||
| 5 | 5 | ||
| 6 | #include <linux/bitfield.h> | 6 | #include <linux/bitfield.h> |
| 7 | #include <linux/bsearch.h> | 7 | #include <linux/bsearch.h> |
| 8 | #include <linux/delay.h> | ||
| 8 | 9 | ||
| 9 | #include <drm/drm_managed.h> | 10 | #include <drm/drm_managed.h> |
| 10 | #include <drm/drm_print.h> | 11 | #include <drm/drm_print.h> |
| @@ -41,6 +42,37 @@ · 30 unmodified lines | |||
| 41 | 42 | ||
| 42 | #define make_u64_from_u32(hi, lo) ((u64)((u64)(u32)(hi) << 32 | (u32)(lo))) | 43 | #define make_u64_from_u32(hi, lo) ((u64)((u64)(u32)(hi) << 32 | (u32)(lo))) |
| 43 | 44 | ||
| 45 | #ifdef CONFIG_DRM_XE_DEBUG | ||
| 46 | enum VF_MIGRATION_WAIT_POINTS { | ||
| 47 | VF_MIGRATION_WAIT_RESFIX_START = BIT(0), | ||
| 48 | VF_MIGRATION_WAIT_FIXUPS = BIT(1), | ||
| 49 | VF_MIGRATION_WAIT_RESTART_JOBS = BIT(2), | ||
| 50 | VF_MIGRATION_WAIT_RESFIX_DONE = BIT(3), | ||
| 51 | }; | ||
| 52 | |||
| 53 | #define VF_MIGRATION_WAIT_DELAY_IN_MS 1000 | ||
| 54 | static void vf_post_migration_inject_wait(struct xe_gt *gt, | ||
| 55 | enum VF_MIGRATION_WAIT_POINTS wait) | ||
| 56 | { | ||
| 57 | while (gt->sriov.vf.migration.debug.resfix_stoppers & wait) { | ||
| 58 | xe_gt_dbg(gt, | ||
| 59 | "*TESTING* injecting %u ms delay due to resfix_stoppers=%#x, to continue clear %#x\n", | ||
| 60 | VF_MIGRATION_WAIT_DELAY_IN_MS, | ||
| 61 | gt->sriov.vf.migration.debug.resfix_stoppers, wait); | ||
| 62 | |||
| 63 | msleep(VF_MIGRATION_WAIT_DELAY_IN_MS); | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | #define VF_MIGRATION_INJECT_WAIT(gt, _POS) ({ \ | ||
| 68 | struct xe_gt *__gt = (gt); \ | ||
| 69 | vf_post_migration_inject_wait(__gt, VF_MIGRATION_WAIT_##_POS); \ | ||
| 70 | }) | ||
| 71 | |||
| 72 | #else | ||
| 73 | #define VF_MIGRATION_INJECT_WAIT(_gt, ...) typecheck(struct xe_gt *, (_gt)) | ||
| 74 | #endif | ||
| 75 | |||
| 44 | static int guc_action_vf_reset(struct xe_guc *guc) | 76 | static int guc_action_vf_reset(struct xe_guc *guc) |
| 45 | { | 77 | { |
| 46 | u32 request[GUC_HXG_REQUEST_MSG_MIN_LEN] = { | 78 | u32 request[GUC_HXG_REQUEST_MSG_MIN_LEN] = { |
| @@ -299,12 +331,13 @@ void xe_gt_sriov_vf_guc_versions(struct xe_gt *gt, · 252 unmodified lines | |||
| 299 | *found = gt->sriov.vf.guc_version; | 331 | *found = gt->sriov.vf.guc_version; |
| 300 | } | 332 | } |
| 301 | 333 | ||
| 302 | static int guc_action_vf_notify_resfix_done(struct xe_guc *guc) | 334 | static int guc_action_vf_resfix_start(struct xe_guc *guc, u16 marker) |
| 303 | { | 335 | { |
| 304 | u32 request[GUC_HXG_REQUEST_MSG_MIN_LEN] = { | 336 | u32 request[GUC_HXG_REQUEST_MSG_MIN_LEN] = { |
| 305 | FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | | 337 | FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | |
| 306 | FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | | 338 | FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | |
| 307 | FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_ACTION_VF2GUC_NOTIFY_RESFIX_DONE), | 339 | FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_ACTION_VF2GUC_RESFIX_START) | |
| 340 | FIELD_PREP(VF2GUC_RESFIX_START_REQUEST_MSG_0_MARKER, marker), | ||
| 308 | }; | 341 | }; |
| 309 | int ret; | 342 | int ret; |
| 310 | 343 | ||
| @@ -313,28 +346,43 @@ static int guc_action_vf_notify_resfix_done(struct xe_guc *guc) · 2 unmodified lines | |||
| 313 | return ret > 0 ? -EPROTO : ret; | 346 | return ret > 0 ? -EPROTO : ret; |
| 314 | } | 347 | } |
| 315 | 348 | ||
| 316 | /** | 349 | static int vf_resfix_start(struct xe_gt *gt, u16 marker) |
| 317 | * vf_notify_resfix_done - Notify GuC about resource fixups apply completed. | ||
| 318 | * @gt: the &xe_gt struct instance linked to target GuC | ||
| 319 | * | ||
| 320 | * Returns: 0 if the operation completed successfully, or a negative error | ||
| 321 | * code otherwise. | ||
| 322 | */ | ||
| 323 | static int vf_notify_resfix_done(struct xe_gt *gt) | ||
| 324 | { | 350 | { |
| 325 | struct xe_guc *guc = >->uc.guc; | 351 | struct xe_guc *guc = >->uc.guc; |
| 326 | int err; | ||
| 327 | 352 | ||
| 328 | xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt))); | 353 | xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt))); |
| 329 | 354 | ||
| 330 | err = guc_action_vf_notify_resfix_done(guc); | 355 | VF_MIGRATION_INJECT_WAIT(gt, RESFIX_START); |
| 331 | if (unlikely(err)) | ||
| 332 | xe_gt_sriov_err(gt, "Failed to notify GuC about resource fixup done (%pe)\n", | ||
| 333 | ERR_PTR(err)); | ||
| 334 | else | ||
| 335 | xe_gt_sriov_dbg_verbose(gt, "sent GuC resource fixup done\n"); | ||
| 336 | 356 | ||
| 337 | return err; | 357 | xe_gt_sriov_dbg_verbose(gt, "Sending resfix start marker %u\n", marker); |
| 358 | |||
| 359 | return guc_action_vf_resfix_start(guc, marker); | ||
| 360 | } | ||
| 361 | |||
| 362 | static int guc_action_vf_resfix_done(struct xe_guc *guc, u16 marker) | ||
| 363 | { | ||
| 364 | u32 request[GUC_HXG_REQUEST_MSG_MIN_LEN] = { | ||
| 365 | FIELD_PREP(GUC_HXG_MSG_0_ORIGIN, GUC_HXG_ORIGIN_HOST) | | ||
| 366 | FIELD_PREP(GUC_HXG_MSG_0_TYPE, GUC_HXG_TYPE_REQUEST) | | ||
| 367 | FIELD_PREP(GUC_HXG_REQUEST_MSG_0_ACTION, GUC_ACTION_VF2GUC_RESFIX_DONE) | | ||
| 368 | FIELD_PREP(VF2GUC_RESFIX_DONE_REQUEST_MSG_0_MARKER, marker), | ||
| 369 | }; | ||
| 370 | int ret; | ||
| 371 | |||
| 372 | ret = xe_guc_mmio_send(guc, request, ARRAY_SIZE(request)); | ||
| 373 | |||
| 374 | return ret > 0 ? -EPROTO : ret; | ||
| 375 | } | ||
| 376 | |||
| 377 | static int vf_resfix_done(struct xe_gt *gt, u16 marker) | ||
| 378 | { | ||
| 379 | struct xe_guc *guc = >->uc.guc; | ||
| 380 | |||
| 381 | xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt))); | ||
| 382 | |||
| 383 | xe_gt_sriov_dbg_verbose(gt, "Sending resfix done marker %u\n", marker); | ||
| 384 | |||
| 385 | return guc_action_vf_resfix_done(guc, marker); | ||
| 338 | } | 386 | } |
| 339 | 387 | ||
| 340 | static int guc_action_query_single_klv(struct xe_guc *guc, u32 key, | 388 | static int guc_action_query_single_klv(struct xe_guc *guc, u32 key, |
| @@ -1123,12 +1171,8 @@ static bool vf_post_migration_shutdown(struct xe_gt *gt) · 782 unmodified lines | |||
| 1123 | return true; | 1171 | return true; |
| 1124 | } | 1172 | } |
| 1125 | 1173 | ||
| 1126 | spin_lock_irq(>->sriov.vf.migration.lock); | ||
| 1127 | gt->sriov.vf.migration.recovery_queued = false; | ||
| 1128 | spin_unlock_irq(>->sriov.vf.migration.lock); | ||
| 1129 | |||
| 1130 | xe_guc_ct_flush_and_stop(>->uc.guc.ct); | 1174 | xe_guc_ct_flush_and_stop(>->uc.guc.ct); |
| 1131 | xe_guc_submit_pause(>->uc.guc); | 1175 | xe_guc_submit_pause_vf(>->uc.guc); |
| 1132 | xe_tlb_inval_reset(>->tlb_inval); | 1176 | xe_tlb_inval_reset(>->tlb_inval); |
| 1133 | 1177 | ||
| 1134 | return false; | 1178 | return false; |
| @@ -1144,6 +1188,8 @@ static int vf_post_migration_fixups(struct xe_gt *gt) · 9 unmodified lines | |||
| 1144 | void *buf = gt->sriov.vf.migration.scratch; | 1188 | void *buf = gt->sriov.vf.migration.scratch; |
| 1145 | int err; | 1189 | int err; |
| 1146 | 1190 | ||
| 1191 | VF_MIGRATION_INJECT_WAIT(gt, FIXUPS); | ||
| 1192 | |||
| 1147 | /* xe_gt_sriov_vf_query_config will fixup the GGTT addresses */ | 1193 | /* xe_gt_sriov_vf_query_config will fixup the GGTT addresses */ |
| 1148 | err = xe_gt_sriov_vf_query_config(gt); | 1194 | err = xe_gt_sriov_vf_query_config(gt); |
| 1149 | if (err) | 1195 | if (err) |
| @@ -1162,13 +1208,22 @@ static int vf_post_migration_fixups(struct xe_gt *gt) · 12 unmodified lines | |||
| 1162 | 1208 | ||
| 1163 | static void vf_post_migration_rearm(struct xe_gt *gt) | 1209 | static void vf_post_migration_rearm(struct xe_gt *gt) |
| 1164 | { | 1210 | { |
| 1211 | VF_MIGRATION_INJECT_WAIT(gt, RESTART_JOBS); | ||
| 1212 | |||
| 1213 | /* | ||
| 1214 | * Make sure interrupts on the new HW are properly set. The GuC IRQ | ||
| 1215 | * must be working at this point, since the recovery did started, | ||
| 1216 | * but the rest was not enabled using the procedure from spec. | ||
| 1217 | */ | ||
| 1218 | xe_irq_resume(gt_to_xe(gt)); | ||
| 1219 | |||
| 1165 | xe_guc_ct_restart(>->uc.guc.ct); | 1220 | xe_guc_ct_restart(>->uc.guc.ct); |
| 1166 | xe_guc_submit_unpause_prepare(>->uc.guc); | 1221 | xe_guc_submit_unpause_prepare_vf(>->uc.guc); |
| 1167 | } | 1222 | } |
| 1168 | 1223 | ||
| 1169 | static void vf_post_migration_kickstart(struct xe_gt *gt) | 1224 | static void vf_post_migration_kickstart(struct xe_gt *gt) |
| 1170 | { | 1225 | { |
| 1171 | xe_guc_submit_unpause(>->uc.guc); | 1226 | xe_guc_submit_unpause_vf(>->uc.guc); |
| 1172 | } | 1227 | } |
| 1173 | 1228 | ||
| 1174 | static void vf_post_migration_abort(struct xe_gt *gt) | 1229 | static void vf_post_migration_abort(struct xe_gt *gt) |
| @@ -1183,37 +1238,49 @@ static void vf_post_migration_abort(struct xe_gt *gt) · 8 unmodified lines | |||
| 1183 | xe_guc_submit_pause_abort(>->uc.guc); | 1238 | xe_guc_submit_pause_abort(>->uc.guc); |
| 1184 | } | 1239 | } |
| 1185 | 1240 | ||
| 1186 | static int vf_post_migration_notify_resfix_done(struct xe_gt *gt) | 1241 | static int vf_post_migration_resfix_done(struct xe_gt *gt, u16 marker) |
| 1187 | { | 1242 | { |
| 1188 | bool skip_resfix = false; | 1243 | VF_MIGRATION_INJECT_WAIT(gt, RESFIX_DONE); |
| 1189 | 1244 | ||
| 1190 | spin_lock_irq(>->sriov.vf.migration.lock); | 1245 | spin_lock_irq(>->sriov.vf.migration.lock); |
| 1191 | if (gt->sriov.vf.migration.recovery_queued) { | 1246 | if (gt->sriov.vf.migration.recovery_queued) |
| 1192 | skip_resfix = true; | 1247 | xe_gt_sriov_dbg(gt, "another recovery imminent\n"); |
| 1193 | xe_gt_sriov_dbg(gt, "another recovery imminent, resfix skipped\n"); | 1248 | else |
| 1194 | } else { | ||
| 1195 | WRITE_ONCE(gt->sriov.vf.migration.recovery_inprogress, false); | 1249 | WRITE_ONCE(gt->sriov.vf.migration.recovery_inprogress, false); |
| 1196 | } | ||
| 1197 | spin_unlock_irq(>->sriov.vf.migration.lock); | 1250 | spin_unlock_irq(>->sriov.vf.migration.lock); |
| 1198 | 1251 | ||
| 1199 | if (skip_resfix) | 1252 | return vf_resfix_done(gt, marker); |
| 1200 | return -EAGAIN; | 1253 | } |
| 1201 | 1254 | ||
| 1202 | /* | 1255 | static int vf_post_migration_resfix_start(struct xe_gt *gt, u16 marker) |
| 1203 | * Make sure interrupts on the new HW are properly set. The GuC IRQ | 1256 | { |
| 1204 | * must be working at this point, since the recovery did started, | 1257 | int err; |
| 1205 | * but the rest was not enabled using the procedure from spec. | 1258 | |
| 1206 | */ | 1259 | err = vf_resfix_start(gt, marker); |
| 1207 | xe_irq_resume(gt_to_xe(gt)); | ||
| 1208 | 1260 | ||
| 1209 | return vf_notify_resfix_done(gt); | 1261 | guard(spinlock_irq) (>->sriov.vf.migration.lock); |
| 1262 | gt->sriov.vf.migration.recovery_queued = false; | ||
| 1263 | |||
| 1264 | return err; | ||
| 1265 | } | ||
| 1266 | |||
| 1267 | static u16 vf_post_migration_next_resfix_marker(struct xe_gt *gt) | ||
| 1268 | { | ||
| 1269 | xe_gt_assert(gt, IS_SRIOV_VF(gt_to_xe(gt))); | ||
| 1270 | |||
| 1271 | BUILD_BUG_ON(1 + ((typeof(gt->sriov.vf.migration.resfix_marker))~0) > | ||
| 1272 | FIELD_MAX(VF2GUC_RESFIX_START_REQUEST_MSG_0_MARKER)); | ||
| 1273 | |||
| 1274 | /* add 1 to avoid zero-marker */ | ||
| 1275 | return 1 + gt->sriov.vf.migration.resfix_marker++; | ||
| 1210 | } | 1276 | } |
| 1211 | 1277 | ||
| 1212 | static void vf_post_migration_recovery(struct xe_gt *gt) | 1278 | static void vf_post_migration_recovery(struct xe_gt *gt) |
| 1213 | { | 1279 | { |
| 1214 | struct xe_device *xe = gt_to_xe(gt); | 1280 | struct xe_device *xe = gt_to_xe(gt); |
| 1215 | int err; | 1281 | u16 marker; |
| 1216 | bool retry; | 1282 | bool retry; |
| 1283 | int err; | ||
| 1217 | 1284 | ||
| 1218 | xe_gt_sriov_dbg(gt, "migration recovery in progress\n"); | 1285 | xe_gt_sriov_dbg(gt, "migration recovery in progress\n"); |
| 1219 | 1286 | ||
| @@ -1227,15 +1294,30 @@ static void vf_post_migration_recovery(struct xe_gt *gt) · 7 unmodified lines | |||
| 1227 | goto fail; | 1294 | goto fail; |
| 1228 | } | 1295 | } |
| 1229 | 1296 | ||
| 1297 | marker = vf_post_migration_next_resfix_marker(gt); | ||
| 1298 | |||
| 1299 | err = vf_post_migration_resfix_start(gt, marker); | ||
| 1300 | if (unlikely(err)) { | ||
| 1301 | xe_gt_sriov_err(gt, "Recovery failed at GuC RESFIX_START step (%pe)\n", | ||
| 1302 | ERR_PTR(err)); | ||
| 1303 | goto fail; | ||
| 1304 | } | ||
| 1305 | |||
| 1230 | err = vf_post_migration_fixups(gt); | 1306 | err = vf_post_migration_fixups(gt); |
| 1231 | if (err) | 1307 | if (err) |
| 1232 | goto fail; | 1308 | goto fail; |
| 1233 | 1309 | ||
| 1234 | vf_post_migration_rearm(gt); | 1310 | vf_post_migration_rearm(gt); |
| 1235 | 1311 | ||
| 1236 | err = vf_post_migration_notify_resfix_done(gt); | 1312 | err = vf_post_migration_resfix_done(gt, marker); |
| 1237 | if (err && err != -EAGAIN) | 1313 | if (err) { |
| 1314 | if (err == -EREMCHG) | ||
| 1315 | goto queue; | ||
| 1316 | |||
| 1317 | xe_gt_sriov_err(gt, "Recovery failed at GuC RESFIX_DONE step (%pe)\n", | ||
| 1318 | ERR_PTR(err)); | ||
| 1238 | goto fail; | 1319 | goto fail; |
| 1320 | } | ||
| 1239 | 1321 | ||
| 1240 | vf_post_migration_kickstart(gt); | 1322 | vf_post_migration_kickstart(gt); |
| 1241 | 1323 | ||
| @@ -69,4 +69,16 @@ void xe_gt_sriov_vf_debugfs_register(struct xe_gt *gt, struct dentry *root) · 68 unmodified lines | |||
| 69 | vfdentry->d_inode->i_private = gt; | 69 | vfdentry->d_inode->i_private = gt; |
| 70 | 70 | ||
| 71 | drm_debugfs_create_files(vf_info, ARRAY_SIZE(vf_info), vfdentry, minor); | 71 | drm_debugfs_create_files(vf_info, ARRAY_SIZE(vf_info), vfdentry, minor); |
| 72 | |||
| 73 | /* | ||
| 74 | * /sys/kernel/debug/dri/BDF/ | ||
| 75 | * ├── tile0 | ||
| 76 | * ├── gt0 | ||
| 77 | * ├── vf | ||
| 78 | * ├── resfix_stoppers | ||
| 79 | */ | ||
| 80 | if (IS_ENABLED(CONFIG_DRM_XE_DEBUG)) { | ||
| 81 | debugfs_create_x8("resfix_stoppers", 0600, vfdentry, | ||
| 82 | >->sriov.vf.migration.debug.resfix_stoppers); | ||
| 83 | } | ||
| 72 | } | 84 | } |
| @@ -52,6 +52,19 @@ struct xe_gt_sriov_vf_migration { · 51 unmodified lines | |||
| 52 | wait_queue_head_t wq; | 52 | wait_queue_head_t wq; |
| 53 | /** @scratch: Scratch memory for VF recovery */ | 53 | /** @scratch: Scratch memory for VF recovery */ |
| 54 | void *scratch; | 54 | void *scratch; |
| 55 | /** @debug: Debug hooks for delaying migration */ | ||
| 56 | struct { | ||
| 57 | /** | ||
| 58 | * @debug.resfix_stoppers: Stop and wait at different stages | ||
| 59 | * during post migration recovery | ||
| 60 | */ | ||
| 61 | u8 resfix_stoppers; | ||
| 62 | } debug; | ||
| 63 | /** | ||
| 64 | * @resfix_marker: Marker sent on start and on end of post-migration | ||
| 65 | * steps. | ||
| 66 | */ | ||
| 67 | u8 resfix_marker; | ||
| 55 | /** @recovery_teardown: VF post migration recovery is being torn down */ | 68 | /** @recovery_teardown: VF post migration recovery is being torn down */ |
| 56 | bool recovery_teardown; | 69 | bool recovery_teardown; |
| 57 | /** @recovery_queued: VF post migration recovery in queued */ | 70 | /** @recovery_queued: VF post migration recovery in queued */ |
| @@ -66,6 +66,16 @@ static const char *const stat_description[__XE_GT_STATS_NUM_IDS] = { · 65 unmodified lines | |||
| 66 | DEF_STAT_STR(SVM_4K_BIND_US, "svm_4K_bind_us"), | 66 | DEF_STAT_STR(SVM_4K_BIND_US, "svm_4K_bind_us"), |
| 67 | DEF_STAT_STR(SVM_64K_BIND_US, "svm_64K_bind_us"), | 67 | DEF_STAT_STR(SVM_64K_BIND_US, "svm_64K_bind_us"), |
| 68 | DEF_STAT_STR(SVM_2M_BIND_US, "svm_2M_bind_us"), | 68 | DEF_STAT_STR(SVM_2M_BIND_US, "svm_2M_bind_us"), |
| 69 | DEF_STAT_STR(HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_COUNT, | ||
| 70 | "hw_engine_group_suspend_lr_queue_count"), | ||
| 71 | DEF_STAT_STR(HW_ENGINE_GROUP_SKIP_LR_QUEUE_COUNT, | ||
| 72 | "hw_engine_group_skip_lr_queue_count"), | ||
| 73 | DEF_STAT_STR(HW_ENGINE_GROUP_WAIT_DMA_QUEUE_COUNT, | ||
| 74 | "hw_engine_group_wait_dma_queue_count"), | ||
| 75 | DEF_STAT_STR(HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_US, | ||
| 76 | "hw_engine_group_suspend_lr_queue_us"), | ||
| 77 | DEF_STAT_STR(HW_ENGINE_GROUP_WAIT_DMA_QUEUE_US, | ||
| 78 | "hw_engine_group_wait_dma_queue_us"), | ||
| 69 | }; | 79 | }; |
| 70 | 80 | ||
| 71 | /** | 81 | /** |
| @@ -6,6 +6,8 @@ · 5 unmodified lines | |||
| 6 | #ifndef _XE_GT_STATS_H_ | 6 | #ifndef _XE_GT_STATS_H_ |
| 7 | #define _XE_GT_STATS_H_ | 7 | #define _XE_GT_STATS_H_ |
| 8 | 8 | ||
| 9 | #include <linux/ktime.h> | ||
| 10 | |||
| 9 | #include "xe_gt_stats_types.h" | 11 | #include "xe_gt_stats_types.h" |
| 10 | 12 | ||
| 11 | struct xe_gt; | 13 | struct xe_gt; |
| @@ -23,4 +25,34 @@ xe_gt_stats_incr(struct xe_gt *gt, const enum xe_gt_stats_id id, · 11 unmodified lines | |||
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | #endif | 27 | #endif |
| 28 | |||
| 29 | /** | ||
| 30 | * xe_gt_stats_ktime_us_delta() - Get delta in microseconds between now and a | ||
| 31 | * start time | ||
| 32 | * @start: Start time | ||
| 33 | * | ||
| 34 | * Helper for GT stats to get delta in microseconds between now and a start | ||
| 35 | * time, compiles out if GT stats are disabled. | ||
| 36 | * | ||
| 37 | * Return: Delta in microseconds between now and a start time | ||
| 38 | */ | ||
| 39 | static inline s64 xe_gt_stats_ktime_us_delta(ktime_t start) | ||
| 40 | { | ||
| 41 | return IS_ENABLED(CONFIG_DEBUG_FS) ? | ||
| 42 | ktime_us_delta(ktime_get(), start) : 0; | ||
| 43 | } | ||
| 44 | |||
| 45 | /** | ||
| 46 | * xe_gt_stats_ktime_get() - Get current ktime | ||
| 47 | * | ||
| 48 | * Helper for GT stats to get current ktime, compiles out if GT stats are | ||
| 49 | * disabled. | ||
| 50 | * | ||
| 51 | * Return: Get current ktime | ||
| 52 | */ | ||
| 53 | static inline ktime_t xe_gt_stats_ktime_get(void) | ||
| 54 | { | ||
| 55 | return IS_ENABLED(CONFIG_DEBUG_FS) ? ktime_get() : 0; | ||
| 56 | } | ||
| 57 | |||
| 26 | #endif | 58 | #endif |
| @@ -44,6 +44,11 @@ enum xe_gt_stats_id { · 43 unmodified lines | |||
| 44 | XE_GT_STATS_ID_SVM_4K_BIND_US, | 44 | XE_GT_STATS_ID_SVM_4K_BIND_US, |
| 45 | XE_GT_STATS_ID_SVM_64K_BIND_US, | 45 | XE_GT_STATS_ID_SVM_64K_BIND_US, |
| 46 | XE_GT_STATS_ID_SVM_2M_BIND_US, | 46 | XE_GT_STATS_ID_SVM_2M_BIND_US, |
| 47 | XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_COUNT, | ||
| 48 | XE_GT_STATS_ID_HW_ENGINE_GROUP_SKIP_LR_QUEUE_COUNT, | ||
| 49 | XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_COUNT, | ||
| 50 | XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_US, | ||
| 51 | XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_US, | ||
| 47 | /* must be the last entry */ | 52 | /* must be the last entry */ |
| 48 | __XE_GT_STATS_NUM_IDS, | 53 | __XE_GT_STATS_NUM_IDS, |
| 49 | }; | 54 | }; |
| @@ -85,7 +85,7 @@ u32 xe_gt_throttle_get_limit_reasons(struct xe_gt *gt) · 84 unmodified lines | |||
| 85 | { | 85 | { |
| 86 | struct xe_device *xe = gt_to_xe(gt); | 86 | struct xe_device *xe = gt_to_xe(gt); |
| 87 | struct xe_reg reg; | 87 | struct xe_reg reg; |
| 88 | u32 val, mask; | 88 | u32 mask; |
| 89 | 89 | ||
| 90 | if (xe_gt_is_media_type(gt)) | 90 | if (xe_gt_is_media_type(gt)) |
| 91 | reg = MTL_MEDIA_PERF_LIMIT_REASONS; | 91 | reg = MTL_MEDIA_PERF_LIMIT_REASONS; |
| @@ -97,11 +97,8 @@ u32 xe_gt_throttle_get_limit_reasons(struct xe_gt *gt) · 5 unmodified lines | |||
| 97 | else | 97 | else |
| 98 | mask = GT0_PERF_LIMIT_REASONS_MASK; | 98 | mask = GT0_PERF_LIMIT_REASONS_MASK; |
| 99 | 99 | ||
| 100 | xe_pm_runtime_get(xe); | 100 | guard(xe_pm_runtime)(xe); |
| 101 | val = xe_mmio_read32(>->mmio, reg) & mask; | 101 | return xe_mmio_read32(>->mmio, reg) & mask; |
| 102 | xe_pm_runtime_put(xe); | ||
| 103 | |||
| 104 | return val; | ||
| 105 | } | 102 | } |
| 106 | 103 | ||
| 107 | static bool is_throttled_by(struct xe_gt *gt, u32 mask) | 104 | static bool is_throttled_by(struct xe_gt *gt, u32 mask) |
| @@ -140,6 +140,11 @@ struct xe_gt { · 139 unmodified lines | |||
| 140 | u64 engine_mask; | 140 | u64 engine_mask; |
| 141 | /** @info.gmdid: raw GMD_ID value from hardware */ | 141 | /** @info.gmdid: raw GMD_ID value from hardware */ |
| 142 | u32 gmdid; | 142 | u32 gmdid; |
| 143 | /** | ||
| 144 | * @multi_queue_engine_class_mask: Bitmask of engine classes with | ||
| 145 | * multi queue support enabled. | ||
| 146 | */ | ||
| 147 | u16 multi_queue_engine_class_mask; | ||
| 143 | /** @info.id: Unique ID of this GT within the PCI Device */ | 148 | /** @info.id: Unique ID of this GT within the PCI Device */ |
| 144 | u8 id; | 149 | u8 id; |
| 145 | /** @info.has_indirect_ring_state: GT has indirect ring state support */ | 150 | /** @info.has_indirect_ring_state: GT has indirect ring state support */ |
| @@ -104,7 +104,7 @@ static u32 guc_ctl_log_params_flags(struct xe_guc *guc) · 103 unmodified lines | |||
| 104 | u32 offset = guc_bo_ggtt_addr(guc, guc->log.bo) >> PAGE_SHIFT; | 104 | u32 offset = guc_bo_ggtt_addr(guc, guc->log.bo) >> PAGE_SHIFT; |
| 105 | u32 flags; | 105 | u32 flags; |
| 106 | 106 | ||
| 107 | #if (((CRASH_BUFFER_SIZE) % SZ_1M) == 0) | 107 | #if (((XE_GUC_LOG_CRASH_DUMP_BUFFER_SIZE) % SZ_1M) == 0) |
| 108 | #define LOG_UNIT SZ_1M | 108 | #define LOG_UNIT SZ_1M |
| 109 | #define LOG_FLAG GUC_LOG_LOG_ALLOC_UNITS | 109 | #define LOG_FLAG GUC_LOG_LOG_ALLOC_UNITS |
| 110 | #else | 110 | #else |
| @@ -112,7 +112,7 @@ static u32 guc_ctl_log_params_flags(struct xe_guc *guc) · 1 unmodified line | |||
| 112 | #define LOG_FLAG 0 | 112 | #define LOG_FLAG 0 |
| 113 | #endif | 113 | #endif |
| 114 | 114 | ||
| 115 | #if (((CAPTURE_BUFFER_SIZE) % SZ_1M) == 0) | 115 | #if (((XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE) % SZ_1M) == 0) |
| 116 | #define CAPTURE_UNIT SZ_1M | 116 | #define CAPTURE_UNIT SZ_1M |
| 117 | #define CAPTURE_FLAG GUC_LOG_CAPTURE_ALLOC_UNITS | 117 | #define CAPTURE_FLAG GUC_LOG_CAPTURE_ALLOC_UNITS |
| 118 | #else | 118 | #else |
| @@ -120,20 +120,21 @@ static u32 guc_ctl_log_params_flags(struct xe_guc *guc) · 1 unmodified line | |||
| 120 | #define CAPTURE_FLAG 0 | 120 | #define CAPTURE_FLAG 0 |
| 121 | #endif | 121 | #endif |
| 122 | 122 | ||
| 123 | BUILD_BUG_ON(!CRASH_BUFFER_SIZE); | 123 | BUILD_BUG_ON(!XE_GUC_LOG_CRASH_DUMP_BUFFER_SIZE); |
| 124 | BUILD_BUG_ON(!IS_ALIGNED(CRASH_BUFFER_SIZE, LOG_UNIT)); | 124 | BUILD_BUG_ON(!IS_ALIGNED(XE_GUC_LOG_CRASH_DUMP_BUFFER_SIZE, LOG_UNIT)); |
| 125 | BUILD_BUG_ON(!DEBUG_BUFFER_SIZE); | 125 | BUILD_BUG_ON(!XE_GUC_LOG_EVENT_DATA_BUFFER_SIZE); |
| 126 | BUILD_BUG_ON(!IS_ALIGNED(DEBUG_BUFFER_SIZE, LOG_UNIT)); | 126 | BUILD_BUG_ON(!IS_ALIGNED(XE_GUC_LOG_EVENT_DATA_BUFFER_SIZE, LOG_UNIT)); |
| 127 | BUILD_BUG_ON(!CAPTURE_BUFFER_SIZE); | 127 | BUILD_BUG_ON(!XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE); |
| 128 | BUILD_BUG_ON(!IS_ALIGNED(CAPTURE_BUFFER_SIZE, CAPTURE_UNIT)); | 128 | BUILD_BUG_ON(!IS_ALIGNED(XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE, CAPTURE_UNIT)); |
| 129 | 129 | ||
| 130 | flags = GUC_LOG_VALID | | 130 | flags = GUC_LOG_VALID | |
| 131 | GUC_LOG_NOTIFY_ON_HALF_FULL | | 131 | GUC_LOG_NOTIFY_ON_HALF_FULL | |
| 132 | CAPTURE_FLAG | | 132 | CAPTURE_FLAG | |
| 133 | LOG_FLAG | | 133 | LOG_FLAG | |
| 134 | FIELD_PREP(GUC_LOG_CRASH, CRASH_BUFFER_SIZE / LOG_UNIT - 1) | | 134 | FIELD_PREP(GUC_LOG_CRASH_DUMP, XE_GUC_LOG_CRASH_DUMP_BUFFER_SIZE / LOG_UNIT - 1) | |
| 135 | FIELD_PREP(GUC_LOG_DEBUG, DEBUG_BUFFER_SIZE / LOG_UNIT - 1) | | 135 | FIELD_PREP(GUC_LOG_EVENT_DATA, XE_GUC_LOG_EVENT_DATA_BUFFER_SIZE / LOG_UNIT - 1) | |
| 136 | FIELD_PREP(GUC_LOG_CAPTURE, CAPTURE_BUFFER_SIZE / CAPTURE_UNIT - 1) | | 136 | FIELD_PREP(GUC_LOG_STATE_CAPTURE, XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE / |
| 137 | CAPTURE_UNIT - 1) | | ||
| 137 | FIELD_PREP(GUC_LOG_BUF_ADDR, offset); | 138 | FIELD_PREP(GUC_LOG_BUF_ADDR, offset); |
| 138 | 139 | ||
| 139 | #undef LOG_UNIT | 140 | #undef LOG_UNIT |
| @@ -660,11 +661,9 @@ static void guc_fini_hw(void *arg) · 520 unmodified lines | |||
| 660 | { | 661 | { |
| 661 | struct xe_guc *guc = arg; | 662 | struct xe_guc *guc = arg; |
| 662 | struct xe_gt *gt = guc_to_gt(guc); | 663 | struct xe_gt *gt = guc_to_gt(guc); |
| 663 | unsigned int fw_ref; | ||
| 664 | 664 | ||
| 665 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | 665 | xe_with_force_wake(fw_ref, gt_to_fw(gt), XE_FORCEWAKE_ALL) |
| 666 | xe_uc_sanitize_reset(&guc_to_gt(guc)->uc); | 666 | xe_uc_sanitize_reset(&guc_to_gt(guc)->uc); |
| 667 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 668 | 667 | ||
| 669 | guc_g2g_fini(guc); | 668 | guc_g2g_fini(guc); |
| 670 | } | 669 | } |
| @@ -768,6 +767,10 @@ int xe_guc_init(struct xe_guc *guc) · 97 unmodified lines | |||
| 768 | if (!xe_uc_fw_is_enabled(&guc->fw)) | 767 | if (!xe_uc_fw_is_enabled(&guc->fw)) |
| 769 | return 0; | 768 | return 0; |
| 770 | 769 | ||
| 770 | /* Disable page reclaim if GuC FW does not support */ | ||
| 771 | if (GUC_SUBMIT_VER(guc) < MAKE_GUC_VER(1, 14, 0)) | ||
| 772 | xe->info.has_page_reclaim_hw_assist = false; | ||
| 773 | |||
| 771 | if (IS_SRIOV_VF(xe)) { | 774 | if (IS_SRIOV_VF(xe)) { |
| 772 | ret = xe_guc_ct_init(&guc->ct); | 775 | ret = xe_guc_ct_init(&guc->ct); |
| 773 | if (ret) | 776 | if (ret) |
| @@ -1485,6 +1488,12 @@ timeout: · 711 unmodified lines | |||
| 1485 | u32 hint = FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, header); | 1488 | u32 hint = FIELD_GET(GUC_HXG_FAILURE_MSG_0_HINT, header); |
| 1486 | u32 error = FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, header); | 1489 | u32 error = FIELD_GET(GUC_HXG_FAILURE_MSG_0_ERROR, header); |
| 1487 | 1490 | ||
| 1491 | if (unlikely(error == XE_GUC_RESPONSE_VF_MIGRATED)) { | ||
| 1492 | xe_gt_dbg(gt, "GuC mmio request %#x rejected due to MIGRATION (hint %#x)\n", | ||
| 1493 | request[0], hint); | ||
| 1494 | return -EREMCHG; | ||
| 1495 | } | ||
| 1496 | |||
| 1488 | xe_gt_err(gt, "GuC mmio request %#x: failure %#x hint %#x\n", | 1497 | xe_gt_err(gt, "GuC mmio request %#x: failure %#x hint %#x\n", |
| 1489 | request[0], error, hint); | 1498 | request[0], error, hint); |
| 1490 | return -ENXIO; | 1499 | return -ENXIO; |
| @@ -1618,18 +1627,51 @@ int xe_guc_start(struct xe_guc *guc) · 127 unmodified lines | |||
| 1618 | return xe_guc_submit_start(guc); | 1627 | return xe_guc_submit_start(guc); |
| 1619 | } | 1628 | } |
| 1620 | 1629 | ||
| 1630 | /** | ||
| 1631 | * xe_guc_runtime_suspend() - GuC runtime suspend | ||
| 1632 | * @guc: The GuC object | ||
| 1633 | * | ||
| 1634 | * Stop further runs of submission tasks on given GuC and runtime suspend | ||
| 1635 | * GuC CT. | ||
| 1636 | */ | ||
| 1637 | void xe_guc_runtime_suspend(struct xe_guc *guc) | ||
| 1638 | { | ||
| 1639 | xe_guc_submit_pause(guc); | ||
| 1640 | xe_guc_submit_disable(guc); | ||
| 1641 | xe_guc_ct_runtime_suspend(&guc->ct); | ||
| 1642 | } | ||
| 1643 | |||
| 1644 | /** | ||
| 1645 | * xe_guc_runtime_resume() - GuC runtime resume | ||
| 1646 | * @guc: The GuC object | ||
| 1647 | * | ||
| 1648 | * Runtime resume GuC CT and allow further runs of submission tasks on | ||
| 1649 | * given GuC. | ||
| 1650 | */ | ||
| 1651 | void xe_guc_runtime_resume(struct xe_guc *guc) | ||
| 1652 | { | ||
| 1653 | /* | ||
| 1654 | * Runtime PM flows are not applicable for VFs, so it's safe to | ||
| 1655 | * directly enable IRQ. | ||
| 1656 | */ | ||
| 1657 | guc_enable_irq(guc); | ||
| 1658 | |||
| 1659 | xe_guc_ct_runtime_resume(&guc->ct); | ||
| 1660 | xe_guc_submit_enable(guc); | ||
| 1661 | xe_guc_submit_unpause(guc); | ||
| 1662 | } | ||
| 1663 | |||
| 1621 | void xe_guc_print_info(struct xe_guc *guc, struct drm_printer *p) | 1664 | void xe_guc_print_info(struct xe_guc *guc, struct drm_printer *p) |
| 1622 | { | 1665 | { |
| 1623 | struct xe_gt *gt = guc_to_gt(guc); | 1666 | struct xe_gt *gt = guc_to_gt(guc); |
| 1624 | unsigned int fw_ref; | ||
| 1625 | u32 status; | 1667 | u32 status; |
| 1626 | int i; | 1668 | int i; |
| 1627 | 1669 | ||
| 1628 | xe_uc_fw_print(&guc->fw, p); | 1670 | xe_uc_fw_print(&guc->fw, p); |
| 1629 | 1671 | ||
| 1630 | if (!IS_SRIOV_VF(gt_to_xe(gt))) { | 1672 | if (!IS_SRIOV_VF(gt_to_xe(gt))) { |
| 1631 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 1673 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 1632 | if (!fw_ref) | 1674 | if (!fw_ref.domains) |
| 1633 | return; | 1675 | return; |
| 1634 | 1676 | ||
| 1635 | status = xe_mmio_read32(>->mmio, GUC_STATUS); | 1677 | status = xe_mmio_read32(>->mmio, GUC_STATUS); |
| @@ -1649,8 +1691,6 @@ void xe_guc_print_info(struct xe_guc *guc, struct drm_printer *p) · 13 unmodified lines | |||
| 1649 | drm_printf(p, "\t%2d: \t0x%x\n", | 1691 | drm_printf(p, "\t%2d: \t0x%x\n", |
| 1650 | i, xe_mmio_read32(>->mmio, SOFT_SCRATCH(i))); | 1692 | i, xe_mmio_read32(>->mmio, SOFT_SCRATCH(i))); |
| 1651 | } | 1693 | } |
| 1652 | |||
| 1653 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 1654 | } | 1694 | } |
| 1655 | 1695 | ||
| 1656 | drm_puts(p, "\n"); | 1696 | drm_puts(p, "\n"); |
| @@ -18,10 +18,16 @@ · 17 unmodified lines | |||
| 18 | */ | 18 | */ |
| 19 | #define MAKE_GUC_VER(maj, min, pat) (((maj) << 16) | ((min) << 8) | (pat)) | 19 | #define MAKE_GUC_VER(maj, min, pat) (((maj) << 16) | ((min) << 8) | (pat)) |
| 20 | #define MAKE_GUC_VER_STRUCT(ver) MAKE_GUC_VER((ver).major, (ver).minor, (ver).patch) | 20 | #define MAKE_GUC_VER_STRUCT(ver) MAKE_GUC_VER((ver).major, (ver).minor, (ver).patch) |
| 21 | #define MAKE_GUC_VER_ARGS(ver...) \ | ||
| 22 | (BUILD_BUG_ON_ZERO(COUNT_ARGS(ver) < 2 || COUNT_ARGS(ver) > 3) + \ | ||
| 23 | MAKE_GUC_VER(PICK_ARG1(ver), PICK_ARG2(ver), IF_ARGS(PICK_ARG3(ver), 0, PICK_ARG3(ver)))) | ||
| 24 | |||
| 21 | #define GUC_SUBMIT_VER(guc) \ | 25 | #define GUC_SUBMIT_VER(guc) \ |
| 22 | MAKE_GUC_VER_STRUCT((guc)->fw.versions.found[XE_UC_FW_VER_COMPATIBILITY]) | 26 | MAKE_GUC_VER_STRUCT((guc)->fw.versions.found[XE_UC_FW_VER_COMPATIBILITY]) |
| 23 | #define GUC_FIRMWARE_VER(guc) \ | 27 | #define GUC_FIRMWARE_VER(guc) \ |
| 24 | MAKE_GUC_VER_STRUCT((guc)->fw.versions.found[XE_UC_FW_VER_RELEASE]) | 28 | MAKE_GUC_VER_STRUCT((guc)->fw.versions.found[XE_UC_FW_VER_RELEASE]) |
| 29 | #define GUC_FIRMWARE_VER_AT_LEAST(guc, ver...) \ | ||
| 30 | xe_guc_fw_version_at_least((guc), MAKE_GUC_VER_ARGS(ver)) | ||
| 25 | 31 | ||
| 26 | struct drm_printer; | 32 | struct drm_printer; |
| 27 | 33 | ||
| @@ -35,6 +41,8 @@ int xe_guc_upload(struct xe_guc *guc); · 7 unmodified lines | |||
| 35 | int xe_guc_min_load_for_hwconfig(struct xe_guc *guc); | 41 | int xe_guc_min_load_for_hwconfig(struct xe_guc *guc); |
| 36 | int xe_guc_enable_communication(struct xe_guc *guc); | 42 | int xe_guc_enable_communication(struct xe_guc *guc); |
| 37 | int xe_guc_opt_in_features_enable(struct xe_guc *guc); | 43 | int xe_guc_opt_in_features_enable(struct xe_guc *guc); |
| 44 | void xe_guc_runtime_suspend(struct xe_guc *guc); | ||
| 45 | void xe_guc_runtime_resume(struct xe_guc *guc); | ||
| 38 | int xe_guc_suspend(struct xe_guc *guc); | 46 | int xe_guc_suspend(struct xe_guc *guc); |
| 39 | void xe_guc_notify(struct xe_guc *guc); | 47 | void xe_guc_notify(struct xe_guc *guc); |
| 40 | int xe_guc_auth_huc(struct xe_guc *guc, u32 rsa_addr); | 48 | int xe_guc_auth_huc(struct xe_guc *guc, u32 rsa_addr); |
| @@ -94,4 +102,19 @@ static inline struct drm_device *guc_to_drm(struct xe_guc *guc) · 53 unmodified lines | |||
| 94 | return &guc_to_xe(guc)->drm; | 102 | return &guc_to_xe(guc)->drm; |
| 95 | } | 103 | } |
| 96 | 104 | ||
| 105 | /** | ||
| 106 | * xe_guc_fw_version_at_least() - Check if GuC is at least of given version. | ||
| 107 | * @guc: the &xe_guc | ||
| 108 | * @ver: the version to check | ||
| 109 | * | ||
| 110 | * The @ver should be prepared using MAKE_GUC_VER(major, minor, patch). | ||
| 111 | * | ||
| 112 | * Return: true if loaded GuC firmware is at least of given version, | ||
| 113 | * false otherwise. | ||
| 114 | */ | ||
| 115 | static inline bool xe_guc_fw_version_at_least(const struct xe_guc *guc, u32 ver) | ||
| 116 | { | ||
| 117 | return GUC_FIRMWARE_VER(guc) >= ver; | ||
| 118 | } | ||
| 119 | |||
| 97 | #endif | 120 | #endif |
| @@ -317,7 +317,7 @@ static void guc_waklv_init(struct xe_guc_ads *ads) · 316 unmodified lines | |||
| 317 | offset = guc_ads_waklv_offset(ads); | 317 | offset = guc_ads_waklv_offset(ads); |
| 318 | remain = guc_ads_waklv_size(ads); | 318 | remain = guc_ads_waklv_size(ads); |
| 319 | 319 | ||
| 320 | if (XE_GT_WA(gt, 14019882105) || XE_GT_WA(gt, 16021333562)) | 320 | if (XE_GT_WA(gt, 16021333562)) |
| 321 | guc_waklv_enable(ads, NULL, 0, &offset, &remain, | 321 | guc_waklv_enable(ads, NULL, 0, &offset, &remain, |
| 322 | GUC_WORKAROUND_KLV_BLOCK_INTERRUPTS_WHEN_MGSR_BLOCKED); | 322 | GUC_WORKAROUND_KLV_BLOCK_INTERRUPTS_WHEN_MGSR_BLOCKED); |
| 323 | if (XE_GT_WA(gt, 18024947630)) | 323 | if (XE_GT_WA(gt, 18024947630)) |
| @@ -347,10 +347,10 @@ static void guc_waklv_init(struct xe_guc_ads *ads) · 23 unmodified lines | |||
| 347 | guc_waklv_enable(ads, NULL, 0, &offset, &remain, | 347 | guc_waklv_enable(ads, NULL, 0, &offset, &remain, |
| 348 | GUC_WORKAROUND_KLV_ID_BACK_TO_BACK_RCS_ENGINE_RESET); | 348 | GUC_WORKAROUND_KLV_ID_BACK_TO_BACK_RCS_ENGINE_RESET); |
| 349 | 349 | ||
| 350 | if (GUC_FIRMWARE_VER(>->uc.guc) >= MAKE_GUC_VER(70, 44, 0) && XE_GT_WA(gt, 16026508708)) | 350 | if (GUC_FIRMWARE_VER_AT_LEAST(>->uc.guc, 70, 44) && XE_GT_WA(gt, 16026508708)) |
| 351 | guc_waklv_enable(ads, NULL, 0, &offset, &remain, | 351 | guc_waklv_enable(ads, NULL, 0, &offset, &remain, |
| 352 | GUC_WA_KLV_RESET_BB_STACK_PTR_ON_VF_SWITCH); | 352 | GUC_WA_KLV_RESET_BB_STACK_PTR_ON_VF_SWITCH); |
| 353 | if (GUC_FIRMWARE_VER(>->uc.guc) >= MAKE_GUC_VER(70, 47, 0) && XE_GT_WA(gt, 16026007364)) { | 353 | if (GUC_FIRMWARE_VER_AT_LEAST(>->uc.guc, 70, 47) && XE_GT_WA(gt, 16026007364)) { |
| 354 | u32 data[] = { | 354 | u32 data[] = { |
| 355 | 0x0, | 355 | 0x0, |
| 356 | 0xF, | 356 | 0xF, |
| @@ -30,7 +30,7 @@ static int guc_buf_cache_init(struct xe_guc_buf_cache *cache, u32 size) · 29 unmodified lines | |||
| 30 | struct xe_gt *gt = cache_to_gt(cache); | 30 | struct xe_gt *gt = cache_to_gt(cache); |
| 31 | struct xe_sa_manager *sam; | 31 | struct xe_sa_manager *sam; |
| 32 | 32 | ||
| 33 | sam = __xe_sa_bo_manager_init(gt_to_tile(gt), size, 0, sizeof(u32)); | 33 | sam = __xe_sa_bo_manager_init(gt_to_tile(gt), size, 0, sizeof(u32), 0); |
| 34 | if (IS_ERR(sam)) | 34 | if (IS_ERR(sam)) |
| 35 | return PTR_ERR(sam); | 35 | return PTR_ERR(sam); |
| 36 | cache->sam = sam; | 36 | cache->sam = sam; |
| @@ -843,7 +843,7 @@ static void check_guc_capture_size(struct xe_guc *guc) · 842 unmodified lines | |||
| 843 | { | 843 | { |
| 844 | int capture_size = guc_capture_output_size_est(guc); | 844 | int capture_size = guc_capture_output_size_est(guc); |
| 845 | int spare_size = capture_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER; | 845 | int spare_size = capture_size * GUC_CAPTURE_OVERBUFFER_MULTIPLIER; |
| 846 | u32 buffer_size = xe_guc_log_section_size_capture(&guc->log); | 846 | u32 buffer_size = XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE; |
| 847 | 847 | ||
| 848 | /* | 848 | /* |
| 849 | * NOTE: capture_size is much smaller than the capture region | 849 | * NOTE: capture_size is much smaller than the capture region |
| @@ -949,7 +949,7 @@ guc_capture_init_node(struct xe_guc *guc, struct __guc_capture_parsed_output *no · 99 unmodified lines | |||
| 949 | * ADS module also calls separately for PF vs VF. | 949 | * ADS module also calls separately for PF vs VF. |
| 950 | * | 950 | * |
| 951 | * --> alloc B: GuC output capture buf (registered via guc_init_params(log_param)) | 951 | * --> alloc B: GuC output capture buf (registered via guc_init_params(log_param)) |
| 952 | * Size = #define CAPTURE_BUFFER_SIZE (warns if on too-small) | 952 | * Size = XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE (warns if on too-small) |
| 953 | * Note2: 'x 3' to hold multiple capture groups | 953 | * Note2: 'x 3' to hold multiple capture groups |
| 954 | * | 954 | * |
| 955 | * GUC Runtime notify capture: | 955 | * GUC Runtime notify capture: |
| @@ -1367,7 +1367,7 @@ static int __guc_capture_flushlog_complete(struct xe_guc *guc) · 411 unmodified lines | |||
| 1367 | { | 1367 | { |
| 1368 | u32 action[] = { | 1368 | u32 action[] = { |
| 1369 | XE_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE, | 1369 | XE_GUC_ACTION_LOG_BUFFER_FILE_FLUSH_COMPLETE, |
| 1370 | GUC_LOG_BUFFER_CAPTURE | 1370 | GUC_LOG_TYPE_STATE_CAPTURE |
| 1371 | }; | 1371 | }; |
| 1372 | 1372 | ||
| 1373 | return xe_guc_ct_send_g2h_handler(&guc->ct, action, ARRAY_SIZE(action)); | 1373 | return xe_guc_ct_send_g2h_handler(&guc->ct, action, ARRAY_SIZE(action)); |
| @@ -1384,8 +1384,8 @@ static void __guc_capture_process_output(struct xe_guc *guc) · 10 unmodified lines | |||
| 1384 | u32 log_buf_state_offset; | 1384 | u32 log_buf_state_offset; |
| 1385 | u32 src_data_offset; | 1385 | u32 src_data_offset; |
| 1386 | 1386 | ||
| 1387 | log_buf_state_offset = sizeof(struct guc_log_buffer_state) * GUC_LOG_BUFFER_CAPTURE; | 1387 | log_buf_state_offset = sizeof(struct guc_log_buffer_state) * GUC_LOG_TYPE_STATE_CAPTURE; |
| 1388 | src_data_offset = xe_guc_get_log_buffer_offset(&guc->log, GUC_LOG_BUFFER_CAPTURE); | 1388 | src_data_offset = XE_GUC_LOG_STATE_CAPTURE_OFFSET; |
| 1389 | 1389 | ||
| 1390 | /* | 1390 | /* |
| 1391 | * Make a copy of the state structure, inside GuC log buffer | 1391 | * Make a copy of the state structure, inside GuC log buffer |
| @@ -1395,15 +1395,15 @@ static void __guc_capture_process_output(struct xe_guc *guc) · 3 unmodified lines | |||
| 1395 | xe_map_memcpy_from(guc_to_xe(guc), &log_buf_state_local, &guc->log.bo->vmap, | 1395 | xe_map_memcpy_from(guc_to_xe(guc), &log_buf_state_local, &guc->log.bo->vmap, |
| 1396 | log_buf_state_offset, sizeof(struct guc_log_buffer_state)); | 1396 | log_buf_state_offset, sizeof(struct guc_log_buffer_state)); |
| 1397 | 1397 | ||
| 1398 | buffer_size = xe_guc_get_log_buffer_size(&guc->log, GUC_LOG_BUFFER_CAPTURE); | 1398 | buffer_size = XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE; |
| 1399 | read_offset = log_buf_state_local.read_ptr; | 1399 | read_offset = log_buf_state_local.read_ptr; |
| 1400 | write_offset = log_buf_state_local.sampled_write_ptr; | 1400 | write_offset = log_buf_state_local.sampled_write_ptr; |
| 1401 | full_count = FIELD_GET(GUC_LOG_BUFFER_STATE_BUFFER_FULL_CNT, log_buf_state_local.flags); | 1401 | full_count = FIELD_GET(GUC_LOG_BUFFER_STATE_BUFFER_FULL_CNT, log_buf_state_local.flags); |
| 1402 | 1402 | ||
| 1403 | /* Bookkeeping stuff */ | 1403 | /* Bookkeeping stuff */ |
| 1404 | tmp = FIELD_GET(GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE, log_buf_state_local.flags); | 1404 | tmp = FIELD_GET(GUC_LOG_BUFFER_STATE_FLUSH_TO_FILE, log_buf_state_local.flags); |
| 1405 | guc->log.stats[GUC_LOG_BUFFER_CAPTURE].flush += tmp; | 1405 | guc->log.stats[GUC_LOG_TYPE_STATE_CAPTURE].flush += tmp; |
| 1406 | new_overflow = xe_guc_check_log_buf_overflow(&guc->log, GUC_LOG_BUFFER_CAPTURE, | 1406 | new_overflow = xe_guc_check_log_buf_overflow(&guc->log, GUC_LOG_TYPE_STATE_CAPTURE, |
| 1407 | full_count); | 1407 | full_count); |
| 1408 | 1408 | ||
| 1409 | /* Now copy the actual logs. */ | 1409 | /* Now copy the actual logs. */ |
| @@ -42,6 +42,21 @@ static void ct_exit_safe_mode(struct xe_guc_ct *ct); · 41 unmodified lines | |||
| 42 | static void guc_ct_change_state(struct xe_guc_ct *ct, | 42 | static void guc_ct_change_state(struct xe_guc_ct *ct, |
| 43 | enum xe_guc_ct_state state); | 43 | enum xe_guc_ct_state state); |
| 44 | 44 | ||
| 45 | static struct xe_guc *ct_to_guc(struct xe_guc_ct *ct) | ||
| 46 | { | ||
| 47 | return container_of(ct, struct xe_guc, ct); | ||
| 48 | } | ||
| 49 | |||
| 50 | static struct xe_gt *ct_to_gt(struct xe_guc_ct *ct) | ||
| 51 | { | ||
| 52 | return container_of(ct, struct xe_gt, uc.guc.ct); | ||
| 53 | } | ||
| 54 | |||
| 55 | static struct xe_device *ct_to_xe(struct xe_guc_ct *ct) | ||
| 56 | { | ||
| 57 | return gt_to_xe(ct_to_gt(ct)); | ||
| 58 | } | ||
| 59 | |||
| 45 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) | 60 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) |
| 46 | enum { | 61 | enum { |
| 47 | /* Internal states, not error conditions */ | 62 | /* Internal states, not error conditions */ |
| @@ -68,14 +83,101 @@ enum { · 20 unmodified lines | |||
| 68 | static void ct_dead_worker_func(struct work_struct *w); | 83 | static void ct_dead_worker_func(struct work_struct *w); |
| 69 | static void ct_dead_capture(struct xe_guc_ct *ct, struct guc_ctb *ctb, u32 reason_code); | 84 | static void ct_dead_capture(struct xe_guc_ct *ct, struct guc_ctb *ctb, u32 reason_code); |
| 70 | 85 | ||
| 71 | #define CT_DEAD(ct, ctb, reason_code) ct_dead_capture((ct), (ctb), CT_DEAD_##reason_code) | 86 | static void ct_dead_fini(struct xe_guc_ct *ct) |
| 87 | { | ||
| 88 | cancel_work_sync(&ct->dead.worker); | ||
| 89 | } | ||
| 90 | |||
| 91 | static void ct_dead_init(struct xe_guc_ct *ct) | ||
| 92 | { | ||
| 93 | spin_lock_init(&ct->dead.lock); | ||
| 94 | INIT_WORK(&ct->dead.worker, ct_dead_worker_func); | ||
| 95 | |||
| 96 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) | ||
| 97 | stack_depot_init(); | ||
| 98 | #endif | ||
| 99 | } | ||
| 100 | |||
| 101 | static void fast_req_stack_save(struct xe_guc_ct *ct, unsigned int slot) | ||
| 102 | { | ||
| 103 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) | ||
| 104 | unsigned long entries[SZ_32]; | ||
| 105 | unsigned int n; | ||
| 106 | |||
| 107 | n = stack_trace_save(entries, ARRAY_SIZE(entries), 1); | ||
| 108 | /* May be called under spinlock, so avoid sleeping */ | ||
| 109 | ct->fast_req[slot].stack = stack_depot_save(entries, n, GFP_NOWAIT); | ||
| 110 | #endif | ||
| 111 | } | ||
| 112 | |||
| 113 | static void fast_req_dump(struct xe_guc_ct *ct, u16 fence, unsigned int slot) | ||
| 114 | { | ||
| 115 | struct xe_gt *gt = ct_to_gt(ct); | ||
| 116 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) | ||
| 117 | char *buf __cleanup(kfree) = kmalloc(SZ_4K, GFP_NOWAIT); | ||
| 118 | |||
| 119 | if (buf && stack_depot_snprint(ct->fast_req[slot].stack, buf, SZ_4K, 0)) | ||
| 120 | xe_gt_err(gt, "Fence 0x%x was used by action %#04x sent at:\n%s\n", | ||
| 121 | fence, ct->fast_req[slot].action, buf); | ||
| 122 | else | ||
| 123 | xe_gt_err(gt, "Fence 0x%x was used by action %#04x [failed to retrieve stack]\n", | ||
| 124 | fence, ct->fast_req[slot].action); | ||
| 125 | #else | ||
| 126 | xe_gt_err(gt, "Fence 0x%x was used by action %#04x\n", | ||
| 127 | fence, ct->fast_req[slot].action); | ||
| 128 | #endif | ||
| 129 | } | ||
| 130 | |||
| 131 | static void fast_req_report(struct xe_guc_ct *ct, u16 fence) | ||
| 132 | { | ||
| 133 | u16 fence_min = U16_MAX, fence_max = 0; | ||
| 134 | struct xe_gt *gt = ct_to_gt(ct); | ||
| 135 | unsigned int n; | ||
| 136 | |||
| 137 | lockdep_assert_held(&ct->lock); | ||
| 138 | |||
| 139 | for (n = 0; n < ARRAY_SIZE(ct->fast_req); n++) { | ||
| 140 | if (ct->fast_req[n].fence < fence_min) | ||
| 141 | fence_min = ct->fast_req[n].fence; | ||
| 142 | if (ct->fast_req[n].fence > fence_max) | ||
| 143 | fence_max = ct->fast_req[n].fence; | ||
| 144 | |||
| 145 | if (ct->fast_req[n].fence != fence) | ||
| 146 | continue; | ||
| 147 | |||
| 148 | return fast_req_dump(ct, fence, n); | ||
| 149 | } | ||
| 150 | |||
| 151 | xe_gt_warn(gt, "Fence 0x%x not found - tracking buffer wrapped? [range = 0x%x -> 0x%x, next = 0x%X]\n", | ||
| 152 | fence, fence_min, fence_max, ct->fence_seqno); | ||
| 153 | } | ||
| 154 | |||
| 155 | static void fast_req_track(struct xe_guc_ct *ct, u16 fence, u16 action) | ||
| 156 | { | ||
| 157 | unsigned int slot = fence % ARRAY_SIZE(ct->fast_req); | ||
| 158 | |||
| 159 | fast_req_stack_save(ct, slot); | ||
| 160 | ct->fast_req[slot].fence = fence; | ||
| 161 | ct->fast_req[slot].action = action; | ||
| 162 | } | ||
| 163 | |||
| 164 | #define CT_DEAD(ct, ctb, reason_code) ct_dead_capture((ct), (ctb), CT_DEAD_##reason_code) | ||
| 165 | |||
| 72 | #else | 166 | #else |
| 167 | |||
| 168 | static void ct_dead_fini(struct xe_guc_ct *ct) { } | ||
| 169 | static void ct_dead_init(struct xe_guc_ct *ct) { } | ||
| 170 | |||
| 171 | static void fast_req_report(struct xe_guc_ct *ct, u16 fence) { } | ||
| 172 | static void fast_req_track(struct xe_guc_ct *ct, u16 fence, u16 action) { } | ||
| 173 | |||
| 73 | #define CT_DEAD(ct, ctb, reason) \ | 174 | #define CT_DEAD(ct, ctb, reason) \ |
| 74 | do { \ | 175 | do { \ |
| 75 | struct guc_ctb *_ctb = (ctb); \ | 176 | struct guc_ctb *_ctb = (ctb); \ |
| 76 | if (_ctb) \ | 177 | if (_ctb) \ |
| 77 | _ctb->info.broken = true; \ | 178 | _ctb->info.broken = true; \ |
| 78 | } while (0) | 179 | } while (0) |
| 180 | |||
| 79 | #endif | 181 | #endif |
| 80 | 182 | ||
| 81 | /* Used when a CT send wants to block and / or receive data */ | 183 | /* Used when a CT send wants to block and / or receive data */ |
| @@ -112,24 +214,6 @@ static bool g2h_fence_needs_alloc(struct g2h_fence *g2h_fence) · 30 unmodified lines | |||
| 112 | return g2h_fence->seqno == ~0x0; | 214 | return g2h_fence->seqno == ~0x0; |
| 113 | } | 215 | } |
| 114 | 216 | ||
| 115 | static struct xe_guc * | ||
| 116 | ct_to_guc(struct xe_guc_ct *ct) | ||
| 117 | { | ||
| 118 | return container_of(ct, struct xe_guc, ct); | ||
| 119 | } | ||
| 120 | |||
| 121 | static struct xe_gt * | ||
| 122 | ct_to_gt(struct xe_guc_ct *ct) | ||
| 123 | { | ||
| 124 | return container_of(ct, struct xe_gt, uc.guc.ct); | ||
| 125 | } | ||
| 126 | |||
| 127 | static struct xe_device * | ||
| 128 | ct_to_xe(struct xe_guc_ct *ct) | ||
| 129 | { | ||
| 130 | return gt_to_xe(ct_to_gt(ct)); | ||
| 131 | } | ||
| 132 | |||
| 133 | /** | 217 | /** |
| 134 | * DOC: GuC CTB Blob | 218 | * DOC: GuC CTB Blob |
| 135 | * | 219 | * |
| @@ -169,8 +253,11 @@ ct_to_xe(struct xe_guc_ct *ct) · 33 unmodified lines | |||
| 169 | #define CTB_DESC_SIZE ALIGN(sizeof(struct guc_ct_buffer_desc), SZ_2K) | 253 | #define CTB_DESC_SIZE ALIGN(sizeof(struct guc_ct_buffer_desc), SZ_2K) |
| 170 | #define CTB_H2G_BUFFER_OFFSET (CTB_DESC_SIZE * 2) | 254 | #define CTB_H2G_BUFFER_OFFSET (CTB_DESC_SIZE * 2) |
| 171 | #define CTB_H2G_BUFFER_SIZE (SZ_4K) | 255 | #define CTB_H2G_BUFFER_SIZE (SZ_4K) |
| 256 | #define CTB_H2G_BUFFER_DWORDS (CTB_H2G_BUFFER_SIZE / sizeof(u32)) | ||
| 172 | #define CTB_G2H_BUFFER_SIZE (SZ_128K) | 257 | #define CTB_G2H_BUFFER_SIZE (SZ_128K) |
| 258 | #define CTB_G2H_BUFFER_DWORDS (CTB_G2H_BUFFER_SIZE / sizeof(u32)) | ||
| 173 | #define G2H_ROOM_BUFFER_SIZE (CTB_G2H_BUFFER_SIZE / 2) | 259 | #define G2H_ROOM_BUFFER_SIZE (CTB_G2H_BUFFER_SIZE / 2) |
| 260 | #define G2H_ROOM_BUFFER_DWORDS (CTB_G2H_BUFFER_DWORDS / 2) | ||
| 174 | 261 | ||
| 175 | /** | 262 | /** |
| 176 | * xe_guc_ct_queue_proc_time_jiffies - Return maximum time to process a full | 263 | * xe_guc_ct_queue_proc_time_jiffies - Return maximum time to process a full |
| @@ -199,9 +286,7 @@ static void guc_ct_fini(struct drm_device *drm, void *arg) · 22 unmodified lines | |||
| 199 | { | 286 | { |
| 200 | struct xe_guc_ct *ct = arg; | 287 | struct xe_guc_ct *ct = arg; |
| 201 | 288 | ||
| 202 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) | 289 | ct_dead_fini(ct); |
| 203 | cancel_work_sync(&ct->dead.worker); | ||
| 204 | #endif | ||
| 205 | ct_exit_safe_mode(ct); | 290 | ct_exit_safe_mode(ct); |
| 206 | destroy_workqueue(ct->g2h_wq); | 291 | destroy_workqueue(ct->g2h_wq); |
| 207 | xa_destroy(&ct->fence_lookup); | 292 | xa_destroy(&ct->fence_lookup); |
| @@ -239,13 +324,8 @@ int xe_guc_ct_init_noalloc(struct xe_guc_ct *ct) · 31 unmodified lines | |||
| 239 | xa_init(&ct->fence_lookup); | 324 | xa_init(&ct->fence_lookup); |
| 240 | INIT_WORK(&ct->g2h_worker, g2h_worker_func); | 325 | INIT_WORK(&ct->g2h_worker, g2h_worker_func); |
| 241 | INIT_DELAYED_WORK(&ct->safe_mode_worker, safe_mode_worker_func); | 326 | INIT_DELAYED_WORK(&ct->safe_mode_worker, safe_mode_worker_func); |
| 242 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) | 327 | |
| 243 | spin_lock_init(&ct->dead.lock); | 328 | ct_dead_init(ct); |
| 244 | INIT_WORK(&ct->dead.worker, ct_dead_worker_func); | ||
| 245 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) | ||
| 246 | stack_depot_init(); | ||
| 247 | #endif | ||
| 248 | #endif | ||
| 249 | init_waitqueue_head(&ct->wq); | 329 | init_waitqueue_head(&ct->wq); |
| 250 | init_waitqueue_head(&ct->g2h_fence_wq); | 330 | init_waitqueue_head(&ct->g2h_fence_wq); |
| 251 | 331 | ||
| @@ -326,7 +406,7 @@ int xe_guc_ct_init_post_hwconfig(struct xe_guc_ct *ct) · 74 unmodified lines | |||
| 326 | static void guc_ct_ctb_h2g_init(struct xe_device *xe, struct guc_ctb *h2g, | 406 | static void guc_ct_ctb_h2g_init(struct xe_device *xe, struct guc_ctb *h2g, |
| 327 | struct iosys_map *map) | 407 | struct iosys_map *map) |
| 328 | { | 408 | { |
| 329 | h2g->info.size = CTB_H2G_BUFFER_SIZE / sizeof(u32); | 409 | h2g->info.size = CTB_H2G_BUFFER_DWORDS; |
| 330 | h2g->info.resv_space = 0; | 410 | h2g->info.resv_space = 0; |
| 331 | h2g->info.tail = 0; | 411 | h2g->info.tail = 0; |
| 332 | h2g->info.head = 0; | 412 | h2g->info.head = 0; |
| @@ -344,8 +424,8 @@ static void guc_ct_ctb_h2g_init(struct xe_device *xe, struct guc_ctb *h2g, · 11 unmodified lines | |||
| 344 | static void guc_ct_ctb_g2h_init(struct xe_device *xe, struct guc_ctb *g2h, | 424 | static void guc_ct_ctb_g2h_init(struct xe_device *xe, struct guc_ctb *g2h, |
| 345 | struct iosys_map *map) | 425 | struct iosys_map *map) |
| 346 | { | 426 | { |
| 347 | g2h->info.size = CTB_G2H_BUFFER_SIZE / sizeof(u32); | 427 | g2h->info.size = CTB_G2H_BUFFER_DWORDS; |
| 348 | g2h->info.resv_space = G2H_ROOM_BUFFER_SIZE / sizeof(u32); | 428 | g2h->info.resv_space = G2H_ROOM_BUFFER_DWORDS; |
| 349 | g2h->info.head = 0; | 429 | g2h->info.head = 0; |
| 350 | g2h->info.tail = 0; | 430 | g2h->info.tail = 0; |
| 351 | g2h->info.space = CIRC_SPACE(g2h->info.tail, g2h->info.head, | 431 | g2h->info.space = CIRC_SPACE(g2h->info.tail, g2h->info.head, |
| @@ -640,6 +720,39 @@ void xe_guc_ct_stop(struct xe_guc_ct *ct) · 288 unmodified lines | |||
| 640 | stop_g2h_handler(ct); | 720 | stop_g2h_handler(ct); |
| 641 | } | 721 | } |
| 642 | 722 | ||
| 723 | /** | ||
| 724 | * xe_guc_ct_runtime_suspend() - GuC CT runtime suspend | ||
| 725 | * @ct: the &xe_guc_ct | ||
| 726 | * | ||
| 727 | * Set GuC CT to disabled state. | ||
| 728 | */ | ||
| 729 | void xe_guc_ct_runtime_suspend(struct xe_guc_ct *ct) | ||
| 730 | { | ||
| 731 | struct guc_ctb *g2h = &ct->ctbs.g2h; | ||
| 732 | u32 credits = CIRC_SPACE(0, 0, CTB_G2H_BUFFER_DWORDS) - G2H_ROOM_BUFFER_DWORDS; | ||
| 733 | |||
| 734 | /* We should be back to guc_ct_ctb_g2h_init() values */ | ||
| 735 | xe_gt_assert(ct_to_gt(ct), g2h->info.space == credits); | ||
| 736 | |||
| 737 | /* | ||
| 738 | * Since we're already in runtime suspend path, we shouldn't have pending | ||
| 739 | * messages. But if there happen to be any, we'd probably want them to be | ||
| 740 | * thrown as errors for further investigation. | ||
| 741 | */ | ||
| 742 | xe_guc_ct_disable(ct); | ||
| 743 | } | ||
| 744 | |||
| 745 | /** | ||
| 746 | * xe_guc_ct_runtime_resume() - GuC CT runtime resume | ||
| 747 | * @ct: the &xe_guc_ct | ||
| 748 | * | ||
| 749 | * Restart GuC CT and set it to enabled state. | ||
| 750 | */ | ||
| 751 | void xe_guc_ct_runtime_resume(struct xe_guc_ct *ct) | ||
| 752 | { | ||
| 753 | xe_guc_ct_restart(ct); | ||
| 754 | } | ||
| 755 | |||
| 643 | static bool h2g_has_room(struct xe_guc_ct *ct, u32 cmd_len) | 756 | static bool h2g_has_room(struct xe_guc_ct *ct, u32 cmd_len) |
| 644 | { | 757 | { |
| 645 | struct guc_ctb *h2g = &ct->ctbs.h2g; | 758 | struct guc_ctb *h2g = &ct->ctbs.h2g; |
| @@ -747,28 +860,6 @@ static void g2h_release_space(struct xe_guc_ct *ct, u32 g2h_len) · 101 unmodified lines | |||
| 747 | spin_unlock_irq(&ct->fast_lock); | 860 | spin_unlock_irq(&ct->fast_lock); |
| 748 | } | 861 | } |
| 749 | 862 | ||
| 750 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) | ||
| 751 | static void fast_req_track(struct xe_guc_ct *ct, u16 fence, u16 action) | ||
| 752 | { | ||
| 753 | unsigned int slot = fence % ARRAY_SIZE(ct->fast_req); | ||
| 754 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) | ||
| 755 | unsigned long entries[SZ_32]; | ||
| 756 | unsigned int n; | ||
| 757 | |||
| 758 | n = stack_trace_save(entries, ARRAY_SIZE(entries), 1); | ||
| 759 | |||
| 760 | /* May be called under spinlock, so avoid sleeping */ | ||
| 761 | ct->fast_req[slot].stack = stack_depot_save(entries, n, GFP_NOWAIT); | ||
| 762 | #endif | ||
| 763 | ct->fast_req[slot].fence = fence; | ||
| 764 | ct->fast_req[slot].action = action; | ||
| 765 | } | ||
| 766 | #else | ||
| 767 | static void fast_req_track(struct xe_guc_ct *ct, u16 fence, u16 action) | ||
| 768 | { | ||
| 769 | } | ||
| 770 | #endif | ||
| 771 | |||
| 772 | /* | 863 | /* |
| 773 | * The CT protocol accepts a 16 bits fence. This field is fully owned by the | 864 | * The CT protocol accepts a 16 bits fence. This field is fully owned by the |
| 774 | * driver, the GuC will just copy it to the reply message. Since we need to | 865 | * driver, the GuC will just copy it to the reply message. Since we need to |
| @@ -1310,10 +1401,12 @@ static int parse_g2h_event(struct xe_guc_ct *ct, u32 *msg, u32 len) · 535 unmodified lines | |||
| 1310 | lockdep_assert_held(&ct->lock); | 1401 | lockdep_assert_held(&ct->lock); |
| 1311 | 1402 | ||
| 1312 | switch (action) { | 1403 | switch (action) { |
| 1404 | case XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CONTEXT_CGP_SYNC_DONE: | ||
| 1313 | case XE_GUC_ACTION_SCHED_CONTEXT_MODE_DONE: | 1405 | case XE_GUC_ACTION_SCHED_CONTEXT_MODE_DONE: |
| 1314 | case XE_GUC_ACTION_DEREGISTER_CONTEXT_DONE: | 1406 | case XE_GUC_ACTION_DEREGISTER_CONTEXT_DONE: |
| 1315 | case XE_GUC_ACTION_SCHED_ENGINE_MODE_DONE: | 1407 | case XE_GUC_ACTION_SCHED_ENGINE_MODE_DONE: |
| 1316 | case XE_GUC_ACTION_TLB_INVALIDATION_DONE: | 1408 | case XE_GUC_ACTION_TLB_INVALIDATION_DONE: |
| 1409 | case XE_GUC_ACTION_PAGE_RECLAMATION_DONE: | ||
| 1317 | g2h_release_space(ct, len); | 1410 | g2h_release_space(ct, len); |
| 1318 | } | 1411 | } |
| 1319 | 1412 | ||
| @@ -1338,55 +1431,6 @@ static int guc_crash_process_msg(struct xe_guc_ct *ct, u32 action) · 18 unmodified lines | |||
| 1338 | return 0; | 1431 | return 0; |
| 1339 | } | 1432 | } |
| 1340 | 1433 | ||
| 1341 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG) | ||
| 1342 | static void fast_req_report(struct xe_guc_ct *ct, u16 fence) | ||
| 1343 | { | ||
| 1344 | u16 fence_min = U16_MAX, fence_max = 0; | ||
| 1345 | struct xe_gt *gt = ct_to_gt(ct); | ||
| 1346 | bool found = false; | ||
| 1347 | unsigned int n; | ||
| 1348 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) | ||
| 1349 | char *buf; | ||
| 1350 | #endif | ||
| 1351 | |||
| 1352 | lockdep_assert_held(&ct->lock); | ||
| 1353 | |||
| 1354 | for (n = 0; n < ARRAY_SIZE(ct->fast_req); n++) { | ||
| 1355 | if (ct->fast_req[n].fence < fence_min) | ||
| 1356 | fence_min = ct->fast_req[n].fence; | ||
| 1357 | if (ct->fast_req[n].fence > fence_max) | ||
| 1358 | fence_max = ct->fast_req[n].fence; | ||
| 1359 | |||
| 1360 | if (ct->fast_req[n].fence != fence) | ||
| 1361 | continue; | ||
| 1362 | found = true; | ||
| 1363 | |||
| 1364 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) | ||
| 1365 | buf = kmalloc(SZ_4K, GFP_NOWAIT); | ||
| 1366 | if (buf && stack_depot_snprint(ct->fast_req[n].stack, buf, SZ_4K, 0)) | ||
| 1367 | xe_gt_err(gt, "Fence 0x%x was used by action %#04x sent at:\n%s", | ||
| 1368 | fence, ct->fast_req[n].action, buf); | ||
| 1369 | else | ||
| 1370 | xe_gt_err(gt, "Fence 0x%x was used by action %#04x [failed to retrieve stack]\n", | ||
| 1371 | fence, ct->fast_req[n].action); | ||
| 1372 | kfree(buf); | ||
| 1373 | #else | ||
| 1374 | xe_gt_err(gt, "Fence 0x%x was used by action %#04x\n", | ||
| 1375 | fence, ct->fast_req[n].action); | ||
| 1376 | #endif | ||
| 1377 | break; | ||
| 1378 | } | ||
| 1379 | |||
| 1380 | if (!found) | ||
| 1381 | xe_gt_warn(gt, "Fence 0x%x not found - tracking buffer wrapped? [range = 0x%x -> 0x%x, next = 0x%X]\n", | ||
| 1382 | fence, fence_min, fence_max, ct->fence_seqno); | ||
| 1383 | } | ||
| 1384 | #else | ||
| 1385 | static void fast_req_report(struct xe_guc_ct *ct, u16 fence) | ||
| 1386 | { | ||
| 1387 | } | ||
| 1388 | #endif | ||
| 1389 | |||
| 1390 | static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) | 1434 | static int parse_g2h_response(struct xe_guc_ct *ct, u32 *msg, u32 len) |
| 1391 | { | 1435 | { |
| 1392 | struct xe_gt *gt = ct_to_gt(ct); | 1436 | struct xe_gt *gt = ct_to_gt(ct); |
| @@ -1549,6 +1593,15 @@ static int process_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) · 156 unmodified lines | |||
| 1549 | ret = xe_guc_pagefault_handler(guc, payload, adj_len); | 1593 | ret = xe_guc_pagefault_handler(guc, payload, adj_len); |
| 1550 | break; | 1594 | break; |
| 1551 | case XE_GUC_ACTION_TLB_INVALIDATION_DONE: | 1595 | case XE_GUC_ACTION_TLB_INVALIDATION_DONE: |
| 1596 | case XE_GUC_ACTION_PAGE_RECLAMATION_DONE: | ||
| 1597 | /* | ||
| 1598 | * Page reclamation is an extension of TLB invalidation. Both | ||
| 1599 | * operations share the same seqno and fence. When either | ||
| 1600 | * action completes, we need to signal the corresponding | ||
| 1601 | * fence. Since the handling logic (lookup fence by seqno, | ||
| 1602 | * fence signalling) is identical, we use the same handler | ||
| 1603 | * for both G2H events. | ||
| 1604 | */ | ||
| 1552 | ret = xe_guc_tlb_inval_done_handler(guc, payload, adj_len); | 1605 | ret = xe_guc_tlb_inval_done_handler(guc, payload, adj_len); |
| 1553 | break; | 1606 | break; |
| 1554 | case XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF: | 1607 | case XE_GUC_ACTION_GUC2PF_RELAY_FROM_VF: |
| @@ -1572,6 +1625,13 @@ static int process_g2h_msg(struct xe_guc_ct *ct, u32 *msg, u32 len) · 17 unmodified lines | |||
| 1572 | ret = xe_guc_g2g_test_notification(guc, payload, adj_len); | 1625 | ret = xe_guc_g2g_test_notification(guc, payload, adj_len); |
| 1573 | break; | 1626 | break; |
| 1574 | #endif | 1627 | #endif |
| 1628 | case XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CONTEXT_CGP_SYNC_DONE: | ||
| 1629 | ret = xe_guc_exec_queue_cgp_sync_done_handler(guc, payload, adj_len); | ||
| 1630 | break; | ||
| 1631 | case XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CGP_CONTEXT_ERROR: | ||
| 1632 | ret = xe_guc_exec_queue_cgp_context_error_handler(guc, payload, | ||
| 1633 | adj_len); | ||
| 1634 | break; | ||
| 1575 | default: | 1635 | default: |
| 1576 | xe_gt_err(gt, "unexpected G2H action 0x%04x\n", action); | 1636 | xe_gt_err(gt, "unexpected G2H action 0x%04x\n", action); |
| 1577 | } | 1637 | } |
| @@ -1714,6 +1774,7 @@ static int g2h_read(struct xe_guc_ct *ct, u32 *msg, bool fast_path) · 136 unmodified lines | |||
| 1714 | switch (action) { | 1774 | switch (action) { |
| 1715 | case XE_GUC_ACTION_REPORT_PAGE_FAULT_REQ_DESC: | 1775 | case XE_GUC_ACTION_REPORT_PAGE_FAULT_REQ_DESC: |
| 1716 | case XE_GUC_ACTION_TLB_INVALIDATION_DONE: | 1776 | case XE_GUC_ACTION_TLB_INVALIDATION_DONE: |
| 1777 | case XE_GUC_ACTION_PAGE_RECLAMATION_DONE: | ||
| 1717 | break; /* Process these in fast-path */ | 1778 | break; /* Process these in fast-path */ |
| 1718 | default: | 1779 | default: |
| 1719 | return 0; | 1780 | return 0; |
| @@ -1750,6 +1811,12 @@ static void g2h_fast_path(struct xe_guc_ct *ct, u32 *msg, u32 len) · 30 unmodified lines | |||
| 1750 | ret = xe_guc_pagefault_handler(guc, payload, adj_len); | 1811 | ret = xe_guc_pagefault_handler(guc, payload, adj_len); |
| 1751 | break; | 1812 | break; |
| 1752 | case XE_GUC_ACTION_TLB_INVALIDATION_DONE: | 1813 | case XE_GUC_ACTION_TLB_INVALIDATION_DONE: |
| 1814 | case XE_GUC_ACTION_PAGE_RECLAMATION_DONE: | ||
| 1815 | /* | ||
| 1816 | * Seqno and fence handling of page reclamation and TLB | ||
| 1817 | * invalidation is identical, so we can use the same handler | ||
| 1818 | * for both actions. | ||
| 1819 | */ | ||
| 1753 | __g2h_release_space(ct, len); | 1820 | __g2h_release_space(ct, len); |
| 1754 | ret = xe_guc_tlb_inval_done_handler(guc, payload, adj_len); | 1821 | ret = xe_guc_tlb_inval_done_handler(guc, payload, adj_len); |
| 1755 | break; | 1822 | break; |
| @@ -17,6 +17,8 @@ int xe_guc_ct_init_post_hwconfig(struct xe_guc_ct *ct); · 16 unmodified lines | |||
| 17 | int xe_guc_ct_enable(struct xe_guc_ct *ct); | 17 | int xe_guc_ct_enable(struct xe_guc_ct *ct); |
| 18 | int xe_guc_ct_restart(struct xe_guc_ct *ct); | 18 | int xe_guc_ct_restart(struct xe_guc_ct *ct); |
| 19 | void xe_guc_ct_disable(struct xe_guc_ct *ct); | 19 | void xe_guc_ct_disable(struct xe_guc_ct *ct); |
| 20 | void xe_guc_ct_runtime_resume(struct xe_guc_ct *ct); | ||
| 21 | void xe_guc_ct_runtime_suspend(struct xe_guc_ct *ct); | ||
| 20 | void xe_guc_ct_stop(struct xe_guc_ct *ct); | 22 | void xe_guc_ct_stop(struct xe_guc_ct *ct); |
| 21 | void xe_guc_ct_flush_and_stop(struct xe_guc_ct *ct); | 23 | void xe_guc_ct_flush_and_stop(struct xe_guc_ct *ct); |
| 22 | void xe_guc_ct_fast_path(struct xe_guc_ct *ct); | 24 | void xe_guc_ct_fast_path(struct xe_guc_ct *ct); |
| @@ -70,13 +70,9 @@ static int guc_debugfs_show(struct seq_file *m, void *data) · 69 unmodified lines | |||
| 70 | struct xe_gt *gt = grandparent->d_inode->i_private; | 70 | struct xe_gt *gt = grandparent->d_inode->i_private; |
| 71 | struct xe_device *xe = gt_to_xe(gt); | 71 | struct xe_device *xe = gt_to_xe(gt); |
| 72 | int (*print)(struct xe_guc *, struct drm_printer *) = node->info_ent->data; | 72 | int (*print)(struct xe_guc *, struct drm_printer *) = node->info_ent->data; |
| 73 | int ret; | ||
| 74 | 73 | ||
| 75 | xe_pm_runtime_get(xe); | 74 | guard(xe_pm_runtime)(xe); |
| 76 | ret = print(>->uc.guc, &p); | 75 | return print(>->uc.guc, &p); |
| 77 | xe_pm_runtime_put(xe); | ||
| 78 | |||
| 79 | return ret; | ||
| 80 | } | 76 | } |
| 81 | 77 | ||
| 82 | static int guc_log(struct xe_guc *guc, struct drm_printer *p) | 78 | static int guc_log(struct xe_guc *guc, struct drm_printer *p) |
| @@ -85,6 +81,12 @@ static int guc_log(struct xe_guc *guc, struct drm_printer *p) · 2 unmodified lines | |||
| 85 | return 0; | 81 | return 0; |
| 86 | } | 82 | } |
| 87 | 83 | ||
| 84 | static int guc_log_lfd(struct xe_guc *guc, struct drm_printer *p) | ||
| 85 | { | ||
| 86 | xe_guc_log_print_lfd(&guc->log, p); | ||
| 87 | return 0; | ||
| 88 | } | ||
| 89 | |||
| 88 | static int guc_log_dmesg(struct xe_guc *guc, struct drm_printer *p) | 90 | static int guc_log_dmesg(struct xe_guc *guc, struct drm_printer *p) |
| 89 | { | 91 | { |
| 90 | xe_guc_log_print_dmesg(&guc->log); | 92 | xe_guc_log_print_dmesg(&guc->log); |
| @@ -121,6 +123,7 @@ static const struct drm_info_list slpc_debugfs_list[] = { · 30 unmodified lines | |||
| 121 | /* everything else should be added here */ | 123 | /* everything else should be added here */ |
| 122 | static const struct drm_info_list pf_only_debugfs_list[] = { | 124 | static const struct drm_info_list pf_only_debugfs_list[] = { |
| 123 | { "guc_log", .show = guc_debugfs_show, .data = guc_log }, | 125 | { "guc_log", .show = guc_debugfs_show, .data = guc_log }, |
| 126 | { "guc_log_lfd", .show = guc_debugfs_show, .data = guc_log_lfd }, | ||
| 124 | { "guc_log_dmesg", .show = guc_debugfs_show, .data = guc_log_dmesg }, | 127 | { "guc_log_dmesg", .show = guc_debugfs_show, .data = guc_log_dmesg }, |
| 125 | }; | 128 | }; |
| 126 | 129 | ||
| @@ -16,6 +16,8 @@ · 15 unmodified lines | |||
| 16 | #define G2H_LEN_DW_DEREGISTER_CONTEXT 3 | 16 | #define G2H_LEN_DW_DEREGISTER_CONTEXT 3 |
| 17 | #define G2H_LEN_DW_TLB_INVALIDATE 3 | 17 | #define G2H_LEN_DW_TLB_INVALIDATE 3 |
| 18 | #define G2H_LEN_DW_G2G_NOTIFY_MIN 3 | 18 | #define G2H_LEN_DW_G2G_NOTIFY_MIN 3 |
| 19 | #define G2H_LEN_DW_MULTI_QUEUE_CONTEXT 3 | ||
| 20 | #define G2H_LEN_DW_PAGE_RECLAMATION 3 | ||
| 19 | 21 | ||
| 20 | #define GUC_ID_MAX 65535 | 22 | #define GUC_ID_MAX 65535 |
| 21 | #define GUC_ID_UNKNOWN 0xffffffff | 23 | #define GUC_ID_UNKNOWN 0xffffffff |
| @@ -62,6 +64,8 @@ struct guc_ctxt_registration_info { · 40 unmodified lines | |||
| 62 | u32 wq_base_lo; | 64 | u32 wq_base_lo; |
| 63 | u32 wq_base_hi; | 65 | u32 wq_base_hi; |
| 64 | u32 wq_size; | 66 | u32 wq_size; |
| 67 | u32 cgp_lo; | ||
| 68 | u32 cgp_hi; | ||
| 65 | u32 hwlrca_lo; | 69 | u32 hwlrca_lo; |
| 66 | u32 hwlrca_hi; | 70 | u32 hwlrca_hi; |
| 67 | }; | 71 | }; |
| @@ -91,9 +95,9 @@ struct guc_update_exec_queue_policy { · 23 unmodified lines | |||
| 91 | #define GUC_LOG_NOTIFY_ON_HALF_FULL BIT(1) | 95 | #define GUC_LOG_NOTIFY_ON_HALF_FULL BIT(1) |
| 92 | #define GUC_LOG_CAPTURE_ALLOC_UNITS BIT(2) | 96 | #define GUC_LOG_CAPTURE_ALLOC_UNITS BIT(2) |
| 93 | #define GUC_LOG_LOG_ALLOC_UNITS BIT(3) | 97 | #define GUC_LOG_LOG_ALLOC_UNITS BIT(3) |
| 94 | #define GUC_LOG_CRASH REG_GENMASK(5, 4) | 98 | #define GUC_LOG_CRASH_DUMP REG_GENMASK(5, 4) |
| 95 | #define GUC_LOG_DEBUG REG_GENMASK(9, 6) | 99 | #define GUC_LOG_EVENT_DATA REG_GENMASK(9, 6) |
| 96 | #define GUC_LOG_CAPTURE REG_GENMASK(11, 10) | 100 | #define GUC_LOG_STATE_CAPTURE REG_GENMASK(11, 10) |
| 97 | #define GUC_LOG_BUF_ADDR REG_GENMASK(31, 12) | 101 | #define GUC_LOG_BUF_ADDR REG_GENMASK(31, 12) |
| 98 | 102 | ||
| 99 | #define GUC_CTL_WA 1 | 103 | #define GUC_CTL_WA 1 |
| @@ -24,6 +24,11 @@ · 23 unmodified lines | |||
| 24 | * ABI and the associated &NAME, that may be used in code or debugfs/sysfs:: | 24 | * ABI and the associated &NAME, that may be used in code or debugfs/sysfs:: |
| 25 | * | 25 | * |
| 26 | * define(TAG, NAME) | 26 | * define(TAG, NAME) |
| 27 | * | ||
| 28 | * If required, KLVs can be labeled with GuC firmware version that added them:: | ||
| 29 | * | ||
| 30 | * define(TAG, NAME, MAJOR, MINOR) | ||
| 31 | * define(TAG, NAME, MAJOR, MINOR, PATCH) | ||
| 27 | */ | 32 | */ |
| 28 | #define MAKE_XE_GUC_KLV_THRESHOLDS_SET(define) \ | 33 | #define MAKE_XE_GUC_KLV_THRESHOLDS_SET(define) \ |
| 29 | define(CAT_ERR, cat_error_count) \ | 34 | define(CAT_ERR, cat_error_count) \ |
| @@ -32,6 +37,7 @@ · 2 unmodified lines | |||
| 32 | define(H2G_STORM, guc_time_us) \ | 37 | define(H2G_STORM, guc_time_us) \ |
| 33 | define(IRQ_STORM, irq_time_us) \ | 38 | define(IRQ_STORM, irq_time_us) \ |
| 34 | define(DOORBELL_STORM, doorbell_time_us) \ | 39 | define(DOORBELL_STORM, doorbell_time_us) \ |
| 40 | define(MULTI_LRC_COUNT, multi_lrc_count, 70, 53)\ | ||
| 35 | /* end */ | 41 | /* end */ |
| 36 | 42 | ||
| 37 | /** | 43 | /** |
| @@ -7,8 +7,10 @@ · 6 unmodified lines | |||
| 7 | 7 | ||
| 8 | #include <linux/fault-inject.h> | 8 | #include <linux/fault-inject.h> |
| 9 | 9 | ||
| 10 | #include <linux/utsname.h> | ||
| 10 | #include <drm/drm_managed.h> | 11 | #include <drm/drm_managed.h> |
| 11 | 12 | ||
| 13 | #include "abi/guc_lfd_abi.h" | ||
| 12 | #include "regs/xe_guc_regs.h" | 14 | #include "regs/xe_guc_regs.h" |
| 13 | #include "xe_bo.h" | 15 | #include "xe_bo.h" |
| 14 | #include "xe_devcoredump.h" | 16 | #include "xe_devcoredump.h" |
| @@ -19,6 +21,77 @@ · 4 unmodified lines | |||
| 19 | #include "xe_mmio.h" | 21 | #include "xe_mmio.h" |
| 20 | #include "xe_module.h" | 22 | #include "xe_module.h" |
| 21 | 23 | ||
| 24 | #define GUC_LOG_CHUNK_SIZE SZ_2M | ||
| 25 | |||
| 26 | /* Magic keys define */ | ||
| 27 | #define GUC_LFD_DRIVER_KEY_STREAMING 0x8086AAAA474C5346 | ||
| 28 | #define GUC_LFD_LOG_BUFFER_MARKER_2 0xDEADFEED | ||
| 29 | #define GUC_LFD_CRASH_DUMP_BUFFER_MARKER_2 0x8086DEAD | ||
| 30 | #define GUC_LFD_STATE_CAPTURE_BUFFER_MARKER_2 0xBEEFFEED | ||
| 31 | #define GUC_LFD_LOG_BUFFER_MARKER_1V2 0xCABBA9E6 | ||
| 32 | #define GUC_LFD_STATE_CAPTURE_BUFFER_MARKER_1V2 0xCABBA9F7 | ||
| 33 | #define GUC_LFD_DATA_HEADER_MAGIC 0x8086 | ||
| 34 | |||
| 35 | /* LFD supported LIC type range */ | ||
| 36 | #define GUC_LIC_TYPE_FIRST GUC_LIC_TYPE_GUC_SW_VERSION | ||
| 37 | #define GUC_LIC_TYPE_LAST GUC_LIC_TYPE_BUILD_PLATFORM_ID | ||
| 38 | #define GUC_LFD_TYPE_FW_RANGE_FIRST GUC_LFD_TYPE_FW_VERSION | ||
| 39 | #define GUC_LFD_TYPE_FW_RANGE_LAST GUC_LFD_TYPE_BUILD_PLATFORM_ID | ||
| 40 | |||
| 41 | #define GUC_LOG_BUFFER_STATE_HEADER_LENGTH 4096 | ||
| 42 | #define GUC_LOG_BUFFER_INIT_CONFIG 3 | ||
| 43 | |||
| 44 | struct guc_log_buffer_entry_list { | ||
| 45 | u32 offset; | ||
| 46 | u32 rd_ptr; | ||
| 47 | u32 wr_ptr; | ||
| 48 | u32 wrap_offset; | ||
| 49 | u32 buf_size; | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct guc_lic_save { | ||
| 53 | u32 version; | ||
| 54 | /* | ||
| 55 | * Array of init config KLV values. | ||
| 56 | * Range from GUC_LOG_LIC_TYPE_FIRST to GUC_LOG_LIC_TYPE_LAST | ||
| 57 | */ | ||
| 58 | u32 values[GUC_LIC_TYPE_LAST - GUC_LIC_TYPE_FIRST + 1]; | ||
| 59 | struct guc_log_buffer_entry_list entry[GUC_LOG_BUFFER_INIT_CONFIG]; | ||
| 60 | }; | ||
| 61 | |||
| 62 | static struct guc_log_buffer_entry_markers { | ||
| 63 | u32 key[2]; | ||
| 64 | } const entry_markers[GUC_LOG_BUFFER_INIT_CONFIG + 1] = { | ||
| 65 | {{ | ||
| 66 | GUC_LFD_LOG_BUFFER_MARKER_1V2, | ||
| 67 | GUC_LFD_LOG_BUFFER_MARKER_2 | ||
| 68 | }}, | ||
| 69 | {{ | ||
| 70 | GUC_LFD_LOG_BUFFER_MARKER_1V2, | ||
| 71 | GUC_LFD_CRASH_DUMP_BUFFER_MARKER_2 | ||
| 72 | }}, | ||
| 73 | {{ | ||
| 74 | GUC_LFD_STATE_CAPTURE_BUFFER_MARKER_1V2, | ||
| 75 | GUC_LFD_STATE_CAPTURE_BUFFER_MARKER_2 | ||
| 76 | }}, | ||
| 77 | {{ | ||
| 78 | GUC_LIC_MAGIC, | ||
| 79 | (FIELD_PREP_CONST(GUC_LIC_VERSION_MASK_MAJOR, GUC_LIC_VERSION_MAJOR) | | ||
| 80 | FIELD_PREP_CONST(GUC_LIC_VERSION_MASK_MINOR, GUC_LIC_VERSION_MINOR)) | ||
| 81 | }} | ||
| 82 | }; | ||
| 83 | |||
| 84 | static struct guc_log_lic_lfd_map { | ||
| 85 | u32 lic; | ||
| 86 | u32 lfd; | ||
| 87 | } const lic_lfd_type_map[] = { | ||
| 88 | {GUC_LIC_TYPE_GUC_SW_VERSION, GUC_LFD_TYPE_FW_VERSION}, | ||
| 89 | {GUC_LIC_TYPE_GUC_DEVICE_ID, GUC_LFD_TYPE_GUC_DEVICE_ID}, | ||
| 90 | {GUC_LIC_TYPE_TSC_FREQUENCY, GUC_LFD_TYPE_TSC_FREQUENCY}, | ||
| 91 | {GUC_LIC_TYPE_GMD_ID, GUC_LFD_TYPE_GMD_ID}, | ||
| 92 | {GUC_LIC_TYPE_BUILD_PLATFORM_ID, GUC_LFD_TYPE_BUILD_PLATFORM_ID} | ||
| 93 | }; | ||
| 94 | |||
| 22 | static struct xe_guc * | 95 | static struct xe_guc * |
| 23 | log_to_guc(struct xe_guc_log *log) | 96 | log_to_guc(struct xe_guc_log *log) |
| 24 | { | 97 | { |
| @@ -37,33 +110,6 @@ log_to_xe(struct xe_guc_log *log) · 12 unmodified lines | |||
| 37 | return gt_to_xe(log_to_gt(log)); | 110 | return gt_to_xe(log_to_gt(log)); |
| 38 | } | 111 | } |
| 39 | 112 | ||
| 40 | static size_t guc_log_size(void) | ||
| 41 | { | ||
| 42 | /* | ||
| 43 | * GuC Log buffer Layout | ||
| 44 | * | ||
| 45 | * +===============================+ 00B | ||
| 46 | * | Crash dump state header | | ||
| 47 | * +-------------------------------+ 32B | ||
| 48 | * | Debug state header | | ||
| 49 | * +-------------------------------+ 64B | ||
| 50 | * | Capture state header | | ||
| 51 | * +-------------------------------+ 96B | ||
| 52 | * | | | ||
| 53 | * +===============================+ PAGE_SIZE (4KB) | ||
| 54 | * | Crash Dump logs | | ||
| 55 | * +===============================+ + CRASH_SIZE | ||
| 56 | * | Debug logs | | ||
| 57 | * +===============================+ + DEBUG_SIZE | ||
| 58 | * | Capture logs | | ||
| 59 | * +===============================+ + CAPTURE_SIZE | ||
| 60 | */ | ||
| 61 | return PAGE_SIZE + CRASH_BUFFER_SIZE + DEBUG_BUFFER_SIZE + | ||
| 62 | CAPTURE_BUFFER_SIZE; | ||
| 63 | } | ||
| 64 | |||
| 65 | #define GUC_LOG_CHUNK_SIZE SZ_2M | ||
| 66 | |||
| 67 | static struct xe_guc_log_snapshot *xe_guc_log_snapshot_alloc(struct xe_guc_log *log, bool atomic) | 113 | static struct xe_guc_log_snapshot *xe_guc_log_snapshot_alloc(struct xe_guc_log *log, bool atomic) |
| 68 | { | 114 | { |
| 69 | struct xe_guc_log_snapshot *snapshot; | 115 | struct xe_guc_log_snapshot *snapshot; |
| @@ -145,7 +191,6 @@ struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log, · 75 unmodified lines | |||
| 145 | struct xe_device *xe = log_to_xe(log); | 191 | struct xe_device *xe = log_to_xe(log); |
| 146 | struct xe_guc *guc = log_to_guc(log); | 192 | struct xe_guc *guc = log_to_guc(log); |
| 147 | struct xe_gt *gt = log_to_gt(log); | 193 | struct xe_gt *gt = log_to_gt(log); |
| 148 | unsigned int fw_ref; | ||
| 149 | size_t remain; | 194 | size_t remain; |
| 150 | int i; | 195 | int i; |
| 151 | 196 | ||
| @@ -165,13 +210,12 @@ struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log, · 13 unmodified lines | |||
| 165 | remain -= size; | 210 | remain -= size; |
| 166 | } | 211 | } |
| 167 | 212 | ||
| 168 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 213 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 169 | if (!fw_ref) { | 214 | if (!fw_ref.domains) |
| 170 | snapshot->stamp = ~0ULL; | 215 | snapshot->stamp = ~0ULL; |
| 171 | } else { | 216 | else |
| 172 | snapshot->stamp = xe_mmio_read64_2x32(>->mmio, GUC_PMTIMESTAMP_LO); | 217 | snapshot->stamp = xe_mmio_read64_2x32(>->mmio, GUC_PMTIMESTAMP_LO); |
| 173 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | 218 | |
| 174 | } | ||
| 175 | snapshot->ktime = ktime_get_boottime_ns(); | 219 | snapshot->ktime = ktime_get_boottime_ns(); |
| 176 | snapshot->level = log->level; | 220 | snapshot->level = log->level; |
| 177 | snapshot->ver_found = guc->fw.versions.found[XE_UC_FW_VER_RELEASE]; | 221 | snapshot->ver_found = guc->fw.versions.found[XE_UC_FW_VER_RELEASE]; |
| @@ -216,6 +260,318 @@ void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_ · 38 unmodified lines | |||
| 216 | } | 260 | } |
| 217 | } | 261 | } |
| 218 | 262 | ||
| 263 | static inline void lfd_output_binary(struct drm_printer *p, char *buf, int buf_size) | ||
| 264 | { | ||
| 265 | seq_write(p->arg, buf, buf_size); | ||
| 266 | } | ||
| 267 | |||
| 268 | static inline int xe_guc_log_add_lfd_header(struct guc_lfd_data *lfd) | ||
| 269 | { | ||
| 270 | lfd->header = FIELD_PREP_CONST(GUC_LFD_DATA_HEADER_MASK_MAGIC, GUC_LFD_DATA_HEADER_MAGIC); | ||
| 271 | return offsetof(struct guc_lfd_data, data); | ||
| 272 | } | ||
| 273 | |||
| 274 | static int xe_guc_log_add_typed_payload(struct drm_printer *p, u32 type, | ||
| 275 | u32 data_len, void *data) | ||
| 276 | { | ||
| 277 | struct guc_lfd_data lfd; | ||
| 278 | int len; | ||
| 279 | |||
| 280 | len = xe_guc_log_add_lfd_header(&lfd); | ||
| 281 | lfd.header |= FIELD_PREP(GUC_LFD_DATA_HEADER_MASK_TYPE, type); | ||
| 282 | /* make length DW aligned */ | ||
| 283 | lfd.data_count = DIV_ROUND_UP(data_len, sizeof(u32)); | ||
| 284 | lfd_output_binary(p, (char *)&lfd, len); | ||
| 285 | |||
| 286 | lfd_output_binary(p, data, data_len); | ||
| 287 | len += lfd.data_count * sizeof(u32); | ||
| 288 | |||
| 289 | return len; | ||
| 290 | } | ||
| 291 | |||
| 292 | static inline int lic_type_to_index(u32 lic_type) | ||
| 293 | { | ||
| 294 | XE_WARN_ON(lic_type < GUC_LIC_TYPE_FIRST || lic_type > GUC_LIC_TYPE_LAST); | ||
| 295 | |||
| 296 | return lic_type - GUC_LIC_TYPE_FIRST; | ||
| 297 | } | ||
| 298 | |||
| 299 | static inline int lfd_type_to_index(u32 lfd_type) | ||
| 300 | { | ||
| 301 | int i, lic_type = 0; | ||
| 302 | |||
| 303 | XE_WARN_ON(lfd_type < GUC_LFD_TYPE_FW_RANGE_FIRST || lfd_type > GUC_LFD_TYPE_FW_RANGE_LAST); | ||
| 304 | |||
| 305 | for (i = 0; i < ARRAY_SIZE(lic_lfd_type_map); i++) | ||
| 306 | if (lic_lfd_type_map[i].lfd == lfd_type) | ||
| 307 | lic_type = lic_lfd_type_map[i].lic; | ||
| 308 | |||
| 309 | /* If not found, lic_type_to_index will warning invalid type */ | ||
| 310 | return lic_type_to_index(lic_type); | ||
| 311 | } | ||
| 312 | |||
| 313 | static int xe_guc_log_add_klv(struct drm_printer *p, u32 lfd_type, | ||
| 314 | struct guc_lic_save *config) | ||
| 315 | { | ||
| 316 | int klv_index = lfd_type_to_index(lfd_type); | ||
| 317 | |||
| 318 | return xe_guc_log_add_typed_payload(p, lfd_type, sizeof(u32), &config->values[klv_index]); | ||
| 319 | } | ||
| 320 | |||
| 321 | static int xe_guc_log_add_os_id(struct drm_printer *p, u32 id) | ||
| 322 | { | ||
| 323 | struct guc_lfd_data_os_info os_id; | ||
| 324 | struct guc_lfd_data lfd; | ||
| 325 | int len, info_len, section_len; | ||
| 326 | char *version; | ||
| 327 | u32 blank = 0; | ||
| 328 | |||
| 329 | len = xe_guc_log_add_lfd_header(&lfd); | ||
| 330 | lfd.header |= FIELD_PREP(GUC_LFD_DATA_HEADER_MASK_TYPE, GUC_LFD_TYPE_OS_ID); | ||
| 331 | |||
| 332 | os_id.os_id = id; | ||
| 333 | section_len = offsetof(struct guc_lfd_data_os_info, build_version); | ||
| 334 | |||
| 335 | version = init_utsname()->release; | ||
| 336 | info_len = strlen(version); | ||
| 337 | |||
| 338 | /* make length DW aligned */ | ||
| 339 | lfd.data_count = DIV_ROUND_UP(section_len + info_len, sizeof(u32)); | ||
| 340 | lfd_output_binary(p, (char *)&lfd, len); | ||
| 341 | lfd_output_binary(p, (char *)&os_id, section_len); | ||
| 342 | lfd_output_binary(p, version, info_len); | ||
| 343 | |||
| 344 | /* Padding with 0 */ | ||
| 345 | section_len = lfd.data_count * sizeof(u32) - section_len - info_len; | ||
| 346 | if (section_len) | ||
| 347 | lfd_output_binary(p, (char *)&blank, section_len); | ||
| 348 | |||
| 349 | len += lfd.data_count * sizeof(u32); | ||
| 350 | return len; | ||
| 351 | } | ||
| 352 | |||
| 353 | static void xe_guc_log_loop_log_init(struct guc_lic *init, struct guc_lic_save *config) | ||
| 354 | { | ||
| 355 | struct guc_klv_generic_dw_t *p = (void *)init->data; | ||
| 356 | int i; | ||
| 357 | |||
| 358 | for (i = 0; i < init->data_count;) { | ||
| 359 | int klv_len = FIELD_GET(GUC_KLV_0_LEN, p->kl) + 1; | ||
| 360 | int key = FIELD_GET(GUC_KLV_0_KEY, p->kl); | ||
| 361 | |||
| 362 | if (key < GUC_LIC_TYPE_FIRST || key > GUC_LIC_TYPE_LAST) { | ||
| 363 | XE_WARN_ON(key < GUC_LIC_TYPE_FIRST || key > GUC_LIC_TYPE_LAST); | ||
| 364 | break; | ||
| 365 | } | ||
| 366 | config->values[lic_type_to_index(key)] = p->value; | ||
| 367 | i += klv_len + 1; /* Whole KLV structure length in dwords */ | ||
| 368 | p = (void *)((u32 *)p + klv_len); | ||
| 369 | } | ||
| 370 | } | ||
| 371 | |||
| 372 | static int find_marker(u32 mark0, u32 mark1) | ||
| 373 | { | ||
| 374 | int i; | ||
| 375 | |||
| 376 | for (i = 0; i < ARRAY_SIZE(entry_markers); i++) | ||
| 377 | if (mark0 == entry_markers[i].key[0] && mark1 == entry_markers[i].key[1]) | ||
| 378 | return i; | ||
| 379 | |||
| 380 | return ARRAY_SIZE(entry_markers); | ||
| 381 | } | ||
| 382 | |||
| 383 | static void xe_guc_log_load_lic(void *guc_log, struct guc_lic_save *config) | ||
| 384 | { | ||
| 385 | u32 offset = GUC_LOG_BUFFER_STATE_HEADER_LENGTH; | ||
| 386 | struct guc_log_buffer_state *p = guc_log; | ||
| 387 | |||
| 388 | config->version = p->version; | ||
| 389 | while (p->marker[0]) { | ||
| 390 | int index; | ||
| 391 | |||
| 392 | index = find_marker(p->marker[0], p->marker[1]); | ||
| 393 | |||
| 394 | if (index < ARRAY_SIZE(entry_markers)) { | ||
| 395 | if (index == GUC_LOG_BUFFER_INIT_CONFIG) { | ||
| 396 | /* Load log init config */ | ||
| 397 | xe_guc_log_loop_log_init((void *)p, config); | ||
| 398 | |||
| 399 | /* LIC structure is the last */ | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | config->entry[index].offset = offset; | ||
| 403 | config->entry[index].rd_ptr = p->read_ptr; | ||
| 404 | config->entry[index].wr_ptr = p->write_ptr; | ||
| 405 | config->entry[index].wrap_offset = p->wrap_offset; | ||
| 406 | config->entry[index].buf_size = p->size; | ||
| 407 | } | ||
| 408 | offset += p->size; | ||
| 409 | p++; | ||
| 410 | } | ||
| 411 | } | ||
| 412 | |||
| 413 | static int | ||
| 414 | xe_guc_log_output_lfd_init(struct drm_printer *p, struct xe_guc_log_snapshot *snapshot, | ||
| 415 | struct guc_lic_save *config) | ||
| 416 | { | ||
| 417 | int type, len; | ||
| 418 | size_t size = 0; | ||
| 419 | |||
| 420 | /* FW required types */ | ||
| 421 | for (type = GUC_LFD_TYPE_FW_RANGE_FIRST; type <= GUC_LFD_TYPE_FW_RANGE_LAST; type++) | ||
| 422 | size += xe_guc_log_add_klv(p, type, config); | ||
| 423 | |||
| 424 | /* KMD required type(s) */ | ||
| 425 | len = xe_guc_log_add_os_id(p, GUC_LFD_OS_TYPE_OSID_LIN); | ||
| 426 | size += len; | ||
| 427 | |||
| 428 | return size; | ||
| 429 | } | ||
| 430 | |||
| 431 | static void | ||
| 432 | xe_guc_log_print_chunks(struct drm_printer *p, struct xe_guc_log_snapshot *snapshot, | ||
| 433 | u32 from, u32 to) | ||
| 434 | { | ||
| 435 | int chunk_from = from % GUC_LOG_CHUNK_SIZE; | ||
| 436 | int chunk_id = from / GUC_LOG_CHUNK_SIZE; | ||
| 437 | int to_chunk_id = to / GUC_LOG_CHUNK_SIZE; | ||
| 438 | int chunk_to = to % GUC_LOG_CHUNK_SIZE; | ||
| 439 | int pos = from; | ||
| 440 | |||
| 441 | do { | ||
| 442 | size_t size = (to_chunk_id == chunk_id ? chunk_to : GUC_LOG_CHUNK_SIZE) - | ||
| 443 | chunk_from; | ||
| 444 | |||
| 445 | lfd_output_binary(p, snapshot->copy[chunk_id] + chunk_from, size); | ||
| 446 | pos += size; | ||
| 447 | chunk_id++; | ||
| 448 | chunk_from = 0; | ||
| 449 | } while (pos < to); | ||
| 450 | } | ||
| 451 | |||
| 452 | static inline int | ||
| 453 | xe_guc_log_add_log_event(struct drm_printer *p, struct xe_guc_log_snapshot *snapshot, | ||
| 454 | struct guc_lic_save *config) | ||
| 455 | { | ||
| 456 | size_t size; | ||
| 457 | u32 data_len, section_len; | ||
| 458 | struct guc_lfd_data lfd; | ||
| 459 | struct guc_log_buffer_entry_list *entry; | ||
| 460 | struct guc_lfd_data_log_events_buf events_buf; | ||
| 461 | |||
| 462 | entry = &config->entry[GUC_LOG_TYPE_EVENT_DATA]; | ||
| 463 | |||
| 464 | /* Skip empty log */ | ||
| 465 | if (entry->rd_ptr == entry->wr_ptr) | ||
| 466 | return 0; | ||
| 467 | |||
| 468 | size = xe_guc_log_add_lfd_header(&lfd); | ||
| 469 | lfd.header |= FIELD_PREP(GUC_LFD_DATA_HEADER_MASK_TYPE, GUC_LFD_TYPE_LOG_EVENTS_BUFFER); | ||
| 470 | events_buf.log_events_format_version = config->version; | ||
| 471 | |||
| 472 | /* Adjust to log_format_buf */ | ||
| 473 | section_len = offsetof(struct guc_lfd_data_log_events_buf, log_event); | ||
| 474 | data_len = section_len; | ||
| 475 | |||
| 476 | /* Calculate data length */ | ||
| 477 | data_len += entry->rd_ptr < entry->wr_ptr ? (entry->wr_ptr - entry->rd_ptr) : | ||
| 478 | (entry->wr_ptr + entry->wrap_offset - entry->rd_ptr); | ||
| 479 | /* make length u32 aligned */ | ||
| 480 | lfd.data_count = DIV_ROUND_UP(data_len, sizeof(u32)); | ||
| 481 | |||
| 482 | /* Output GUC_LFD_TYPE_LOG_EVENTS_BUFFER header */ | ||
| 483 | lfd_output_binary(p, (char *)&lfd, size); | ||
| 484 | lfd_output_binary(p, (char *)&events_buf, section_len); | ||
| 485 | |||
| 486 | /* Output data from guc log chunks directly */ | ||
| 487 | if (entry->rd_ptr < entry->wr_ptr) { | ||
| 488 | xe_guc_log_print_chunks(p, snapshot, entry->offset + entry->rd_ptr, | ||
| 489 | entry->offset + entry->wr_ptr); | ||
| 490 | } else { | ||
| 491 | /* 1st, print from rd to wrap offset */ | ||
| 492 | xe_guc_log_print_chunks(p, snapshot, entry->offset + entry->rd_ptr, | ||
| 493 | entry->offset + entry->wrap_offset); | ||
| 494 | |||
| 495 | /* 2nd, print from buf start to wr */ | ||
| 496 | xe_guc_log_print_chunks(p, snapshot, entry->offset, entry->offset + entry->wr_ptr); | ||
| 497 | } | ||
| 498 | return size; | ||
| 499 | } | ||
| 500 | |||
| 501 | static int | ||
| 502 | xe_guc_log_add_crash_dump(struct drm_printer *p, struct xe_guc_log_snapshot *snapshot, | ||
| 503 | struct guc_lic_save *config) | ||
| 504 | { | ||
| 505 | struct guc_log_buffer_entry_list *entry; | ||
| 506 | int chunk_from, chunk_id; | ||
| 507 | int from, to, i; | ||
| 508 | size_t size = 0; | ||
| 509 | u32 *buf32; | ||
| 510 | |||
| 511 | entry = &config->entry[GUC_LOG_TYPE_CRASH_DUMP]; | ||
| 512 | |||
| 513 | /* Skip zero sized crash dump */ | ||
| 514 | if (!entry->buf_size) | ||
| 515 | return 0; | ||
| 516 | |||
| 517 | /* Check if crash dump section are all zero */ | ||
| 518 | from = entry->offset; | ||
| 519 | to = entry->offset + entry->buf_size; | ||
| 520 | chunk_from = from % GUC_LOG_CHUNK_SIZE; | ||
| 521 | chunk_id = from / GUC_LOG_CHUNK_SIZE; | ||
| 522 | buf32 = snapshot->copy[chunk_id] + chunk_from; | ||
| 523 | |||
| 524 | for (i = 0; i < entry->buf_size / sizeof(u32); i++) | ||
| 525 | if (buf32[i]) | ||
| 526 | break; | ||
| 527 | |||
| 528 | /* Buffer has non-zero data? */ | ||
| 529 | if (i < entry->buf_size / sizeof(u32)) { | ||
| 530 | struct guc_lfd_data lfd; | ||
| 531 | |||
| 532 | size = xe_guc_log_add_lfd_header(&lfd); | ||
| 533 | lfd.header |= FIELD_PREP(GUC_LFD_DATA_HEADER_MASK_TYPE, GUC_LFD_TYPE_FW_CRASH_DUMP); | ||
| 534 | /* Calculate data length */ | ||
| 535 | lfd.data_count = DIV_ROUND_UP(entry->buf_size, sizeof(u32)); | ||
| 536 | /* Output GUC_LFD_TYPE_FW_CRASH_DUMP header */ | ||
| 537 | lfd_output_binary(p, (char *)&lfd, size); | ||
| 538 | |||
| 539 | /* rd/wr ptr is not used for crash dump */ | ||
| 540 | xe_guc_log_print_chunks(p, snapshot, from, to); | ||
| 541 | } | ||
| 542 | return size; | ||
| 543 | } | ||
| 544 | |||
| 545 | static void | ||
| 546 | xe_guc_log_snapshot_print_lfd(struct xe_guc_log_snapshot *snapshot, struct drm_printer *p) | ||
| 547 | { | ||
| 548 | struct guc_lfd_file_header header; | ||
| 549 | struct guc_lic_save config; | ||
| 550 | size_t size; | ||
| 551 | |||
| 552 | if (!snapshot || !snapshot->size) | ||
| 553 | return; | ||
| 554 | |||
| 555 | header.magic = GUC_LFD_DRIVER_KEY_STREAMING; | ||
| 556 | header.version = FIELD_PREP_CONST(GUC_LFD_FILE_HEADER_VERSION_MASK_MINOR, | ||
| 557 | GUC_LFD_FORMAT_VERSION_MINOR) | | ||
| 558 | FIELD_PREP_CONST(GUC_LFD_FILE_HEADER_VERSION_MASK_MAJOR, | ||
| 559 | GUC_LFD_FORMAT_VERSION_MAJOR); | ||
| 560 | |||
| 561 | /* Output LFD file header */ | ||
| 562 | lfd_output_binary(p, (char *)&header, | ||
| 563 | offsetof(struct guc_lfd_file_header, stream)); | ||
| 564 | |||
| 565 | /* Output LFD stream */ | ||
| 566 | xe_guc_log_load_lic(snapshot->copy[0], &config); | ||
| 567 | size = xe_guc_log_output_lfd_init(p, snapshot, &config); | ||
| 568 | if (!size) | ||
| 569 | return; | ||
| 570 | |||
| 571 | xe_guc_log_add_log_event(p, snapshot, &config); | ||
| 572 | xe_guc_log_add_crash_dump(p, snapshot, &config); | ||
| 573 | } | ||
| 574 | |||
| 219 | /** | 575 | /** |
| 220 | * xe_guc_log_print_dmesg - dump a copy of the GuC log to dmesg | 576 | * xe_guc_log_print_dmesg - dump a copy of the GuC log to dmesg |
| 221 | * @log: GuC log structure | 577 | * @log: GuC log structure |
| @@ -251,13 +607,27 @@ void xe_guc_log_print(struct xe_guc_log *log, struct drm_printer *p) · 29 unmodified lines | |||
| 251 | xe_guc_log_snapshot_free(snapshot); | 607 | xe_guc_log_snapshot_free(snapshot); |
| 252 | } | 608 | } |
| 253 | 609 | ||
| 610 | /** | ||
| 611 | * xe_guc_log_print_lfd - dump a copy of the GuC log in LFD format | ||
| 612 | * @log: GuC log structure | ||
| 613 | * @p: the printer object to output to | ||
| 614 | */ | ||
| 615 | void xe_guc_log_print_lfd(struct xe_guc_log *log, struct drm_printer *p) | ||
| 616 | { | ||
| 617 | struct xe_guc_log_snapshot *snapshot; | ||
| 618 | |||
| 619 | snapshot = xe_guc_log_snapshot_capture(log, false); | ||
| 620 | xe_guc_log_snapshot_print_lfd(snapshot, p); | ||
| 621 | xe_guc_log_snapshot_free(snapshot); | ||
| 622 | } | ||
| 623 | |||
| 254 | int xe_guc_log_init(struct xe_guc_log *log) | 624 | int xe_guc_log_init(struct xe_guc_log *log) |
| 255 | { | 625 | { |
| 256 | struct xe_device *xe = log_to_xe(log); | 626 | struct xe_device *xe = log_to_xe(log); |
| 257 | struct xe_tile *tile = gt_to_tile(log_to_gt(log)); | 627 | struct xe_tile *tile = gt_to_tile(log_to_gt(log)); |
| 258 | struct xe_bo *bo; | 628 | struct xe_bo *bo; |
| 259 | 629 | ||
| 260 | bo = xe_managed_bo_create_pin_map(xe, tile, guc_log_size(), | 630 | bo = xe_managed_bo_create_pin_map(xe, tile, GUC_LOG_SIZE, |
| 261 | XE_BO_FLAG_SYSTEM | | 631 | XE_BO_FLAG_SYSTEM | |
| 262 | XE_BO_FLAG_GGTT | | 632 | XE_BO_FLAG_GGTT | |
| 263 | XE_BO_FLAG_GGTT_INVALIDATE | | 633 | XE_BO_FLAG_GGTT_INVALIDATE | |
| @@ -265,7 +635,7 @@ int xe_guc_log_init(struct xe_guc_log *log) · 1 unmodified line | |||
| 265 | if (IS_ERR(bo)) | 635 | if (IS_ERR(bo)) |
| 266 | return PTR_ERR(bo); | 636 | return PTR_ERR(bo); |
| 267 | 637 | ||
| 268 | xe_map_memset(xe, &bo->vmap, 0, 0, guc_log_size()); | 638 | xe_map_memset(xe, &bo->vmap, 0, 0, xe_bo_size(bo)); |
| 269 | log->bo = bo; | 639 | log->bo = bo; |
| 270 | log->level = xe_modparam.guc_log_level; | 640 | log->level = xe_modparam.guc_log_level; |
| 271 | 641 | ||
| @@ -274,71 +644,6 @@ int xe_guc_log_init(struct xe_guc_log *log) · 2 unmodified lines | |||
| 274 | 644 | ||
| 275 | ALLOW_ERROR_INJECTION(xe_guc_log_init, ERRNO); /* See xe_pci_probe() */ | 645 | ALLOW_ERROR_INJECTION(xe_guc_log_init, ERRNO); /* See xe_pci_probe() */ |
| 276 | 646 | ||
| 277 | static u32 xe_guc_log_section_size_crash(struct xe_guc_log *log) | ||
| 278 | { | ||
| 279 | return CRASH_BUFFER_SIZE; | ||
| 280 | } | ||
| 281 | |||
| 282 | static u32 xe_guc_log_section_size_debug(struct xe_guc_log *log) | ||
| 283 | { | ||
| 284 | return DEBUG_BUFFER_SIZE; | ||
| 285 | } | ||
| 286 | |||
| 287 | /** | ||
| 288 | * xe_guc_log_section_size_capture - Get capture buffer size within log sections. | ||
| 289 | * @log: The log object. | ||
| 290 | * | ||
| 291 | * This function will return the capture buffer size within log sections. | ||
| 292 | * | ||
| 293 | * Return: capture buffer size. | ||
| 294 | */ | ||
| 295 | u32 xe_guc_log_section_size_capture(struct xe_guc_log *log) | ||
| 296 | { | ||
| 297 | return CAPTURE_BUFFER_SIZE; | ||
| 298 | } | ||
| 299 | |||
| 300 | /** | ||
| 301 | * xe_guc_get_log_buffer_size - Get log buffer size for a type. | ||
| 302 | * @log: The log object. | ||
| 303 | * @type: The log buffer type | ||
| 304 | * | ||
| 305 | * Return: buffer size. | ||
| 306 | */ | ||
| 307 | u32 xe_guc_get_log_buffer_size(struct xe_guc_log *log, enum guc_log_buffer_type type) | ||
| 308 | { | ||
| 309 | switch (type) { | ||
| 310 | case GUC_LOG_BUFFER_CRASH_DUMP: | ||
| 311 | return xe_guc_log_section_size_crash(log); | ||
| 312 | case GUC_LOG_BUFFER_DEBUG: | ||
| 313 | return xe_guc_log_section_size_debug(log); | ||
| 314 | case GUC_LOG_BUFFER_CAPTURE: | ||
| 315 | return xe_guc_log_section_size_capture(log); | ||
| 316 | } | ||
| 317 | return 0; | ||
| 318 | } | ||
| 319 | |||
| 320 | /** | ||
| 321 | * xe_guc_get_log_buffer_offset - Get offset in log buffer for a type. | ||
| 322 | * @log: The log object. | ||
| 323 | * @type: The log buffer type | ||
| 324 | * | ||
| 325 | * This function will return the offset in the log buffer for a type. | ||
| 326 | * Return: buffer offset. | ||
| 327 | */ | ||
| 328 | u32 xe_guc_get_log_buffer_offset(struct xe_guc_log *log, enum guc_log_buffer_type type) | ||
| 329 | { | ||
| 330 | enum guc_log_buffer_type i; | ||
| 331 | u32 offset = PAGE_SIZE;/* for the log_buffer_states */ | ||
| 332 | |||
| 333 | for (i = GUC_LOG_BUFFER_CRASH_DUMP; i < GUC_LOG_BUFFER_TYPE_MAX; ++i) { | ||
| 334 | if (i == type) | ||
| 335 | break; | ||
| 336 | offset += xe_guc_get_log_buffer_size(log, i); | ||
| 337 | } | ||
| 338 | |||
| 339 | return offset; | ||
| 340 | } | ||
| 341 | |||
| 342 | /** | 647 | /** |
| 343 | * xe_guc_check_log_buf_overflow - Check if log buffer overflowed | 648 | * xe_guc_check_log_buf_overflow - Check if log buffer overflowed |
| 344 | * @log: The log object. | 649 | * @log: The log object. |
| @@ -352,7 +657,7 @@ u32 xe_guc_get_log_buffer_offset(struct xe_guc_log *log, enum guc_log_buffer_typ · 7 unmodified lines | |||
| 352 | * | 657 | * |
| 353 | * Return: True if overflowed. | 658 | * Return: True if overflowed. |
| 354 | */ | 659 | */ |
| 355 | bool xe_guc_check_log_buf_overflow(struct xe_guc_log *log, enum guc_log_buffer_type type, | 660 | bool xe_guc_check_log_buf_overflow(struct xe_guc_log *log, enum guc_log_type type, |
| 356 | unsigned int full_cnt) | 661 | unsigned int full_cnt) |
| 357 | { | 662 | { |
| 358 | unsigned int prev_full_cnt = log->stats[type].sampled_overflow; | 663 | unsigned int prev_full_cnt = log->stats[type].sampled_overflow; |
| @@ -13,14 +13,26 @@ struct drm_printer; · 12 unmodified lines | |||
| 13 | struct xe_device; | 13 | struct xe_device; |
| 14 | 14 | ||
| 15 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) | 15 | #if IS_ENABLED(CONFIG_DRM_XE_DEBUG_GUC) |
| 16 | #define CRASH_BUFFER_SIZE SZ_1M | 16 | #define XE_GUC_LOG_EVENT_DATA_BUFFER_SIZE SZ_8M |
| 17 | #define DEBUG_BUFFER_SIZE SZ_8M | 17 | #define XE_GUC_LOG_CRASH_DUMP_BUFFER_SIZE SZ_1M |
| 18 | #define CAPTURE_BUFFER_SIZE SZ_2M | 18 | #define XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE SZ_2M |
| 19 | #else | 19 | #else |
| 20 | #define CRASH_BUFFER_SIZE SZ_16K | 20 | #define XE_GUC_LOG_EVENT_DATA_BUFFER_SIZE SZ_64K |
| 21 | #define DEBUG_BUFFER_SIZE SZ_64K | 21 | #define XE_GUC_LOG_CRASH_DUMP_BUFFER_SIZE SZ_16K |
| 22 | #define CAPTURE_BUFFER_SIZE SZ_1M | 22 | #define XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE SZ_1M |
| 23 | #endif | 23 | #endif |
| 24 | |||
| 25 | #define GUC_LOG_SIZE (SZ_4K + \ | ||
| 26 | XE_GUC_LOG_EVENT_DATA_BUFFER_SIZE + \ | ||
| 27 | XE_GUC_LOG_CRASH_DUMP_BUFFER_SIZE + \ | ||
| 28 | XE_GUC_LOG_STATE_CAPTURE_BUFFER_SIZE) | ||
| 29 | |||
| 30 | #define XE_GUC_LOG_EVENT_DATA_OFFSET SZ_4K | ||
| 31 | #define XE_GUC_LOG_CRASH_DUMP_OFFSET (XE_GUC_LOG_EVENT_DATA_OFFSET + \ | ||
| 32 | XE_GUC_LOG_EVENT_DATA_BUFFER_SIZE) | ||
| 33 | #define XE_GUC_LOG_STATE_CAPTURE_OFFSET (XE_GUC_LOG_CRASH_DUMP_OFFSET + \ | ||
| 34 | XE_GUC_LOG_CRASH_DUMP_BUFFER_SIZE) | ||
| 35 | |||
| 24 | /* | 36 | /* |
| 25 | * While we're using plain log level in i915, GuC controls are much more... | 37 | * While we're using plain log level in i915, GuC controls are much more... |
| 26 | * "elaborate"? We have a couple of bits for verbosity, separate bit for actual | 38 | * "elaborate"? We have a couple of bits for verbosity, separate bit for actual |
| @@ -40,6 +52,7 @@ struct xe_device; · 13 unmodified lines | |||
| 40 | 52 | ||
| 41 | int xe_guc_log_init(struct xe_guc_log *log); | 53 | int xe_guc_log_init(struct xe_guc_log *log); |
| 42 | void xe_guc_log_print(struct xe_guc_log *log, struct drm_printer *p); | 54 | void xe_guc_log_print(struct xe_guc_log *log, struct drm_printer *p); |
| 55 | void xe_guc_log_print_lfd(struct xe_guc_log *log, struct drm_printer *p); | ||
| 43 | void xe_guc_log_print_dmesg(struct xe_guc_log *log); | 56 | void xe_guc_log_print_dmesg(struct xe_guc_log *log); |
| 44 | struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log, bool atomic); | 57 | struct xe_guc_log_snapshot *xe_guc_log_snapshot_capture(struct xe_guc_log *log, bool atomic); |
| 45 | void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_printer *p); | 58 | void xe_guc_log_snapshot_print(struct xe_guc_log_snapshot *snapshot, struct drm_printer *p); |
| @@ -51,11 +64,8 @@ xe_guc_log_get_level(struct xe_guc_log *log) · 5 unmodified lines | |||
| 51 | return log->level; | 64 | return log->level; |
| 52 | } | 65 | } |
| 53 | 66 | ||
| 54 | u32 xe_guc_log_section_size_capture(struct xe_guc_log *log); | ||
| 55 | u32 xe_guc_get_log_buffer_size(struct xe_guc_log *log, enum guc_log_buffer_type type); | ||
| 56 | u32 xe_guc_get_log_buffer_offset(struct xe_guc_log *log, enum guc_log_buffer_type type); | ||
| 57 | bool xe_guc_check_log_buf_overflow(struct xe_guc_log *log, | 67 | bool xe_guc_check_log_buf_overflow(struct xe_guc_log *log, |
| 58 | enum guc_log_buffer_type type, | 68 | enum guc_log_type type, |
| 59 | unsigned int full_cnt); | 69 | unsigned int full_cnt); |
| 60 | 70 | ||
| 61 | #endif | 71 | #endif |
| @@ -76,7 +76,7 @@ · 75 unmodified lines | |||
| 76 | * exposes a programming interface to the host for the control of SLPC. | 76 | * exposes a programming interface to the host for the control of SLPC. |
| 77 | * | 77 | * |
| 78 | * Frequency management: | 78 | * Frequency management: |
| 79 | * ===================== | 79 | * --------------------- |
| 80 | * | 80 | * |
| 81 | * Xe driver enables SLPC with all of its defaults features and frequency | 81 | * Xe driver enables SLPC with all of its defaults features and frequency |
| 82 | * selection, which varies per platform. | 82 | * selection, which varies per platform. |
| @@ -87,7 +87,7 @@ · 4 unmodified lines | |||
| 87 | * for any workload. | 87 | * for any workload. |
| 88 | * | 88 | * |
| 89 | * Render-C States: | 89 | * Render-C States: |
| 90 | * ================ | 90 | * ---------------- |
| 91 | * | 91 | * |
| 92 | * Render-C states is also a GuC PC feature that is now enabled in Xe for | 92 | * Render-C states is also a GuC PC feature that is now enabled in Xe for |
| 93 | * all platforms. | 93 | * all platforms. |
| @@ -499,21 +499,17 @@ u32 xe_guc_pc_get_cur_freq_fw(struct xe_guc_pc *pc) · 405 unmodified lines | |||
| 499 | int xe_guc_pc_get_cur_freq(struct xe_guc_pc *pc, u32 *freq) | 499 | int xe_guc_pc_get_cur_freq(struct xe_guc_pc *pc, u32 *freq) |
| 500 | { | 500 | { |
| 501 | struct xe_gt *gt = pc_to_gt(pc); | 501 | struct xe_gt *gt = pc_to_gt(pc); |
| 502 | unsigned int fw_ref; | ||
| 503 | 502 | ||
| 504 | /* | 503 | /* |
| 505 | * GuC SLPC plays with cur freq request when GuCRC is enabled | 504 | * GuC SLPC plays with cur freq request when GuCRC is enabled |
| 506 | * Block RC6 for a more reliable read. | 505 | * Block RC6 for a more reliable read. |
| 507 | */ | 506 | */ |
| 508 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 507 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 509 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) { | 508 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT)) |
| 510 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 511 | return -ETIMEDOUT; | 509 | return -ETIMEDOUT; |
| 512 | } | ||
| 513 | 510 | ||
| 514 | *freq = get_cur_freq(gt); | 511 | *freq = get_cur_freq(gt); |
| 515 | 512 | ||
| 516 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 517 | return 0; | 513 | return 0; |
| 518 | } | 514 | } |
| 519 | 515 | ||
| @@ -1087,13 +1083,8 @@ int xe_guc_pc_gucrc_disable(struct xe_guc_pc *pc) · 567 unmodified lines | |||
| 1087 | */ | 1083 | */ |
| 1088 | int xe_guc_pc_override_gucrc_mode(struct xe_guc_pc *pc, enum slpc_gucrc_mode mode) | 1084 | int xe_guc_pc_override_gucrc_mode(struct xe_guc_pc *pc, enum slpc_gucrc_mode mode) |
| 1089 | { | 1085 | { |
| 1090 | int ret; | 1086 | guard(xe_pm_runtime)(pc_to_xe(pc)); |
| 1091 | 1087 | return pc_action_set_param(pc, SLPC_PARAM_PWRGATE_RC_MODE, mode); | |
| 1092 | xe_pm_runtime_get(pc_to_xe(pc)); | ||
| 1093 | ret = pc_action_set_param(pc, SLPC_PARAM_PWRGATE_RC_MODE, mode); | ||
| 1094 | xe_pm_runtime_put(pc_to_xe(pc)); | ||
| 1095 | |||
| 1096 | return ret; | ||
| 1097 | } | 1088 | } |
| 1098 | 1089 | ||
| 1099 | /** | 1090 | /** |
| @@ -1104,13 +1095,8 @@ int xe_guc_pc_override_gucrc_mode(struct xe_guc_pc *pc, enum slpc_gucrc_mode mod · 4 unmodified lines | |||
| 1104 | */ | 1095 | */ |
| 1105 | int xe_guc_pc_unset_gucrc_mode(struct xe_guc_pc *pc) | 1096 | int xe_guc_pc_unset_gucrc_mode(struct xe_guc_pc *pc) |
| 1106 | { | 1097 | { |
| 1107 | int ret; | 1098 | guard(xe_pm_runtime)(pc_to_xe(pc)); |
| 1108 | 1099 | return pc_action_unset_param(pc, SLPC_PARAM_PWRGATE_RC_MODE); | |
| 1109 | xe_pm_runtime_get(pc_to_xe(pc)); | ||
| 1110 | ret = pc_action_unset_param(pc, SLPC_PARAM_PWRGATE_RC_MODE); | ||
| 1111 | xe_pm_runtime_put(pc_to_xe(pc)); | ||
| 1112 | |||
| 1113 | return ret; | ||
| 1114 | } | 1100 | } |
| 1115 | 1101 | ||
| 1116 | static void pc_init_pcode_freq(struct xe_guc_pc *pc) | 1102 | static void pc_init_pcode_freq(struct xe_guc_pc *pc) |
| @@ -1198,7 +1184,7 @@ int xe_guc_pc_set_power_profile(struct xe_guc_pc *pc, const char *buf) · 81 unmodified lines | |||
| 1198 | return -EINVAL; | 1184 | return -EINVAL; |
| 1199 | 1185 | ||
| 1200 | guard(mutex)(&pc->freq_lock); | 1186 | guard(mutex)(&pc->freq_lock); |
| 1201 | xe_pm_runtime_get_noresume(pc_to_xe(pc)); | 1187 | guard(xe_pm_runtime_noresume)(pc_to_xe(pc)); |
| 1202 | 1188 | ||
| 1203 | ret = pc_action_set_param(pc, | 1189 | ret = pc_action_set_param(pc, |
| 1204 | SLPC_PARAM_POWER_PROFILE, | 1190 | SLPC_PARAM_POWER_PROFILE, |
| @@ -1209,8 +1195,6 @@ int xe_guc_pc_set_power_profile(struct xe_guc_pc *pc, const char *buf) · 4 unmodified lines | |||
| 1209 | else | 1195 | else |
| 1210 | pc->power_profile = val; | 1196 | pc->power_profile = val; |
| 1211 | 1197 | ||
| 1212 | xe_pm_runtime_put(pc_to_xe(pc)); | ||
| 1213 | |||
| 1214 | return ret; | 1198 | return ret; |
| 1215 | } | 1199 | } |
| 1216 | 1200 | ||
| @@ -1223,17 +1207,14 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) · 6 unmodified lines | |||
| 1223 | struct xe_device *xe = pc_to_xe(pc); | 1207 | struct xe_device *xe = pc_to_xe(pc); |
| 1224 | struct xe_gt *gt = pc_to_gt(pc); | 1208 | struct xe_gt *gt = pc_to_gt(pc); |
| 1225 | u32 size = PAGE_ALIGN(sizeof(struct slpc_shared_data)); | 1209 | u32 size = PAGE_ALIGN(sizeof(struct slpc_shared_data)); |
| 1226 | unsigned int fw_ref; | ||
| 1227 | ktime_t earlier; | 1210 | ktime_t earlier; |
| 1228 | int ret; | 1211 | int ret; |
| 1229 | 1212 | ||
| 1230 | xe_gt_assert(gt, xe_device_uc_enabled(xe)); | 1213 | xe_gt_assert(gt, xe_device_uc_enabled(xe)); |
| 1231 | 1214 | ||
| 1232 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 1215 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 1233 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) { | 1216 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT)) |
| 1234 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 1235 | return -ETIMEDOUT; | 1217 | return -ETIMEDOUT; |
| 1236 | } | ||
| 1237 | 1218 | ||
| 1238 | if (xe->info.skip_guc_pc) { | 1219 | if (xe->info.skip_guc_pc) { |
| 1239 | if (xe->info.platform != XE_PVC) | 1220 | if (xe->info.platform != XE_PVC) |
| @@ -1241,9 +1222,7 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) · 1 unmodified line | |||
| 1241 | 1222 | ||
| 1242 | /* Request max possible since dynamic freq mgmt is not enabled */ | 1223 | /* Request max possible since dynamic freq mgmt is not enabled */ |
| 1243 | pc_set_cur_freq(pc, UINT_MAX); | 1224 | pc_set_cur_freq(pc, UINT_MAX); |
| 1244 | 1225 | return 0; | |
| 1245 | ret = 0; | ||
| 1246 | goto out; | ||
| 1247 | } | 1226 | } |
| 1248 | 1227 | ||
| 1249 | xe_map_memset(xe, &pc->bo->vmap, 0, 0, size); | 1228 | xe_map_memset(xe, &pc->bo->vmap, 0, 0, size); |
| @@ -1252,7 +1231,7 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) · 2 unmodified lines | |||
| 1252 | earlier = ktime_get(); | 1231 | earlier = ktime_get(); |
| 1253 | ret = pc_action_reset(pc); | 1232 | ret = pc_action_reset(pc); |
| 1254 | if (ret) | 1233 | if (ret) |
| 1255 | goto out; | 1234 | return ret; |
| 1256 | 1235 | ||
| 1257 | if (wait_for_pc_state(pc, SLPC_GLOBAL_STATE_RUNNING, | 1236 | if (wait_for_pc_state(pc, SLPC_GLOBAL_STATE_RUNNING, |
| 1258 | SLPC_RESET_TIMEOUT_MS)) { | 1237 | SLPC_RESET_TIMEOUT_MS)) { |
| @@ -1263,8 +1242,7 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) · 4 unmodified lines | |||
| 1263 | if (wait_for_pc_state(pc, SLPC_GLOBAL_STATE_RUNNING, | 1242 | if (wait_for_pc_state(pc, SLPC_GLOBAL_STATE_RUNNING, |
| 1264 | SLPC_RESET_EXTENDED_TIMEOUT_MS)) { | 1243 | SLPC_RESET_EXTENDED_TIMEOUT_MS)) { |
| 1265 | xe_gt_err(gt, "GuC PC Start failed: Dynamic GT frequency control and GT sleep states are now disabled.\n"); | 1244 | xe_gt_err(gt, "GuC PC Start failed: Dynamic GT frequency control and GT sleep states are now disabled.\n"); |
| 1266 | ret = -EIO; | 1245 | return -EIO; |
| 1267 | goto out; | ||
| 1268 | } | 1246 | } |
| 1269 | 1247 | ||
| 1270 | xe_gt_warn(gt, "GuC PC excessive start time: %lldms", | 1248 | xe_gt_warn(gt, "GuC PC excessive start time: %lldms", |
| @@ -1273,21 +1251,20 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) · 2 unmodified lines | |||
| 1273 | 1251 | ||
| 1274 | ret = pc_init_freqs(pc); | 1252 | ret = pc_init_freqs(pc); |
| 1275 | if (ret) | 1253 | if (ret) |
| 1276 | goto out; | 1254 | return ret; |
| 1277 | 1255 | ||
| 1278 | ret = pc_set_mert_freq_cap(pc); | 1256 | ret = pc_set_mert_freq_cap(pc); |
| 1279 | if (ret) | 1257 | if (ret) |
| 1280 | goto out; | 1258 | return ret; |
| 1281 | 1259 | ||
| 1282 | if (xe->info.platform == XE_PVC) { | 1260 | if (xe->info.platform == XE_PVC) { |
| 1283 | xe_guc_pc_gucrc_disable(pc); | 1261 | xe_guc_pc_gucrc_disable(pc); |
| 1284 | ret = 0; | 1262 | return 0; |
| 1285 | goto out; | ||
| 1286 | } | 1263 | } |
| 1287 | 1264 | ||
| 1288 | ret = pc_action_setup_gucrc(pc, GUCRC_FIRMWARE_CONTROL); | 1265 | ret = pc_action_setup_gucrc(pc, GUCRC_FIRMWARE_CONTROL); |
| 1289 | if (ret) | 1266 | if (ret) |
| 1290 | goto out; | 1267 | return ret; |
| 1291 | 1268 | ||
| 1292 | /* Enable SLPC Optimized Strategy for compute */ | 1269 | /* Enable SLPC Optimized Strategy for compute */ |
| 1293 | ret = pc_action_set_strategy(pc, SLPC_OPTIMIZED_STRATEGY_COMPUTE); | 1270 | ret = pc_action_set_strategy(pc, SLPC_OPTIMIZED_STRATEGY_COMPUTE); |
| @@ -1297,8 +1274,6 @@ int xe_guc_pc_start(struct xe_guc_pc *pc) · 3 unmodified lines | |||
| 1297 | if (unlikely(ret)) | 1274 | if (unlikely(ret)) |
| 1298 | xe_gt_err(gt, "Failed to set SLPC power profile: %pe\n", ERR_PTR(ret)); | 1275 | xe_gt_err(gt, "Failed to set SLPC power profile: %pe\n", ERR_PTR(ret)); |
| 1299 | 1276 | ||
| 1300 | out: | ||
| 1301 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 1302 | return ret; | 1277 | return ret; |
| 1303 | } | 1278 | } |
| 1304 | 1279 | ||
| @@ -1330,19 +1305,16 @@ static void xe_guc_pc_fini_hw(void *arg) · 25 unmodified lines | |||
| 1330 | { | 1305 | { |
| 1331 | struct xe_guc_pc *pc = arg; | 1306 | struct xe_guc_pc *pc = arg; |
| 1332 | struct xe_device *xe = pc_to_xe(pc); | 1307 | struct xe_device *xe = pc_to_xe(pc); |
| 1333 | unsigned int fw_ref; | ||
| 1334 | 1308 | ||
| 1335 | if (xe_device_wedged(xe)) | 1309 | if (xe_device_wedged(xe)) |
| 1336 | return; | 1310 | return; |
| 1337 | 1311 | ||
| 1338 | fw_ref = xe_force_wake_get(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL); | 1312 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(pc_to_gt(pc)), XE_FORCEWAKE_ALL); |
| 1339 | xe_guc_pc_gucrc_disable(pc); | 1313 | xe_guc_pc_gucrc_disable(pc); |
| 1340 | XE_WARN_ON(xe_guc_pc_stop(pc)); | 1314 | XE_WARN_ON(xe_guc_pc_stop(pc)); |
| 1341 | 1315 | ||
| 1342 | /* Bind requested freq to mert_freq_cap before unload */ | 1316 | /* Bind requested freq to mert_freq_cap before unload */ |
| 1343 | pc_set_cur_freq(pc, min(pc_max_freq_cap(pc), xe_guc_pc_get_rpe_freq(pc))); | 1317 | pc_set_cur_freq(pc, min(pc_max_freq_cap(pc), xe_guc_pc_get_rpe_freq(pc))); |
| 1344 | |||
| 1345 | xe_force_wake_put(gt_to_fw(pc_to_gt(pc)), fw_ref); | ||
| 1346 | } | 1318 | } |
| 1347 | 1319 | ||
| 1348 | /** | 1320 | /** |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | |||
| 19 | #include "abi/guc_klvs_abi.h" | 19 | #include "abi/guc_klvs_abi.h" |
| 20 | #include "regs/xe_lrc_layout.h" | 20 | #include "regs/xe_lrc_layout.h" |
| 21 | #include "xe_assert.h" | 21 | #include "xe_assert.h" |
| 22 | #include "xe_bo.h" | ||
| 22 | #include "xe_devcoredump.h" | 23 | #include "xe_devcoredump.h" |
| 23 | #include "xe_device.h" | 24 | #include "xe_device.h" |
| 24 | #include "xe_exec_queue.h" | 25 | #include "xe_exec_queue.h" |
| @@ -47,6 +48,8 @@ · 22 unmodified lines | |||
| 47 | #include "xe_uc_fw.h" | 48 | #include "xe_uc_fw.h" |
| 48 | #include "xe_vm.h" | 49 | #include "xe_vm.h" |
| 49 | 50 | ||
| 51 | #define XE_GUC_EXEC_QUEUE_CGP_CONTEXT_ERROR_LEN 6 | ||
| 52 | |||
| 50 | static struct xe_guc * | 53 | static struct xe_guc * |
| 51 | exec_queue_to_guc(struct xe_exec_queue *q) | 54 | exec_queue_to_guc(struct xe_exec_queue *q) |
| 52 | { | 55 | { |
| @@ -72,6 +75,7 @@ exec_queue_to_guc(struct xe_exec_queue *q) · 19 unmodified lines | |||
| 72 | #define EXEC_QUEUE_STATE_EXTRA_REF (1 << 11) | 75 | #define EXEC_QUEUE_STATE_EXTRA_REF (1 << 11) |
| 73 | #define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 12) | 76 | #define EXEC_QUEUE_STATE_PENDING_RESUME (1 << 12) |
| 74 | #define EXEC_QUEUE_STATE_PENDING_TDR_EXIT (1 << 13) | 77 | #define EXEC_QUEUE_STATE_PENDING_TDR_EXIT (1 << 13) |
| 78 | #define EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND (1 << 14) | ||
| 75 | 79 | ||
| 76 | static bool exec_queue_registered(struct xe_exec_queue *q) | 80 | static bool exec_queue_registered(struct xe_exec_queue *q) |
| 77 | { | 81 | { |
| @@ -263,6 +267,21 @@ static void clear_exec_queue_pending_tdr_exit(struct xe_exec_queue *q) · 185 unmodified lines | |||
| 263 | atomic_and(~EXEC_QUEUE_STATE_PENDING_TDR_EXIT, &q->guc->state); | 267 | atomic_and(~EXEC_QUEUE_STATE_PENDING_TDR_EXIT, &q->guc->state); |
| 264 | } | 268 | } |
| 265 | 269 | ||
| 270 | static bool exec_queue_idle_skip_suspend(struct xe_exec_queue *q) | ||
| 271 | { | ||
| 272 | return atomic_read(&q->guc->state) & EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND; | ||
| 273 | } | ||
| 274 | |||
| 275 | static void set_exec_queue_idle_skip_suspend(struct xe_exec_queue *q) | ||
| 276 | { | ||
| 277 | atomic_or(EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND, &q->guc->state); | ||
| 278 | } | ||
| 279 | |||
| 280 | static void clear_exec_queue_idle_skip_suspend(struct xe_exec_queue *q) | ||
| 281 | { | ||
| 282 | atomic_and(~EXEC_QUEUE_STATE_IDLE_SKIP_SUSPEND, &q->guc->state); | ||
| 283 | } | ||
| 284 | |||
| 266 | static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q) | 285 | static bool exec_queue_killed_or_banned_or_wedged(struct xe_exec_queue *q) |
| 267 | { | 286 | { |
| 268 | return (atomic_read(&q->guc->state) & | 287 | return (atomic_read(&q->guc->state) & |
| @@ -541,7 +560,8 @@ static void init_policies(struct xe_guc *guc, struct xe_exec_queue *q) · 272 unmodified lines | |||
| 541 | u32 slpc_exec_queue_freq_req = 0; | 560 | u32 slpc_exec_queue_freq_req = 0; |
| 542 | u32 preempt_timeout_us = q->sched_props.preempt_timeout_us; | 561 | u32 preempt_timeout_us = q->sched_props.preempt_timeout_us; |
| 543 | 562 | ||
| 544 | xe_gt_assert(guc_to_gt(guc), exec_queue_registered(q)); | 563 | xe_gt_assert(guc_to_gt(guc), exec_queue_registered(q) && |
| 564 | !xe_exec_queue_is_multi_queue_secondary(q)); | ||
| 545 | 565 | ||
| 546 | if (q->flags & EXEC_QUEUE_FLAG_LOW_LATENCY) | 566 | if (q->flags & EXEC_QUEUE_FLAG_LOW_LATENCY) |
| 547 | slpc_exec_queue_freq_req |= SLPC_CTX_FREQ_REQ_IS_COMPUTE; | 567 | slpc_exec_queue_freq_req |= SLPC_CTX_FREQ_REQ_IS_COMPUTE; |
| @@ -561,6 +581,8 @@ static void set_min_preemption_timeout(struct xe_guc *guc, struct xe_exec_queue · 13 unmodified lines | |||
| 561 | { | 581 | { |
| 562 | struct exec_queue_policy policy; | 582 | struct exec_queue_policy policy; |
| 563 | 583 | ||
| 584 | xe_assert(guc_to_xe(guc), !xe_exec_queue_is_multi_queue_secondary(q)); | ||
| 585 | |||
| 564 | __guc_exec_queue_policy_start_klv(&policy, q->guc->id); | 586 | __guc_exec_queue_policy_start_klv(&policy, q->guc->id); |
| 565 | __guc_exec_queue_policy_add_preemption_timeout(&policy, 1); | 587 | __guc_exec_queue_policy_add_preemption_timeout(&policy, 1); |
| 566 | 588 | ||
| @@ -568,6 +590,89 @@ static void set_min_preemption_timeout(struct xe_guc *guc, struct xe_exec_queue · 1 unmodified line | |||
| 568 | __guc_exec_queue_policy_action_size(&policy), 0, 0); | 590 | __guc_exec_queue_policy_action_size(&policy), 0, 0); |
| 569 | } | 591 | } |
| 570 | 592 | ||
| 593 | static bool vf_recovery(struct xe_guc *guc) | ||
| 594 | { | ||
| 595 | return xe_gt_recovery_pending(guc_to_gt(guc)); | ||
| 596 | } | ||
| 597 | |||
| 598 | static void xe_guc_exec_queue_trigger_cleanup(struct xe_exec_queue *q) | ||
| 599 | { | ||
| 600 | struct xe_guc *guc = exec_queue_to_guc(q); | ||
| 601 | struct xe_device *xe = guc_to_xe(guc); | ||
| 602 | |||
| 603 | /** to wakeup xe_wait_user_fence ioctl if exec queue is reset */ | ||
| 604 | wake_up_all(&xe->ufence_wq); | ||
| 605 | |||
| 606 | if (xe_exec_queue_is_lr(q)) | ||
| 607 | queue_work(guc_to_gt(guc)->ordered_wq, &q->guc->lr_tdr); | ||
| 608 | else | ||
| 609 | xe_sched_tdr_queue_imm(&q->guc->sched); | ||
| 610 | } | ||
| 611 | |||
| 612 | static void xe_guc_exec_queue_group_trigger_cleanup(struct xe_exec_queue *q) | ||
| 613 | { | ||
| 614 | struct xe_exec_queue *primary = xe_exec_queue_multi_queue_primary(q); | ||
| 615 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 616 | struct xe_exec_queue *eq; | ||
| 617 | |||
| 618 | xe_gt_assert(guc_to_gt(exec_queue_to_guc(q)), | ||
| 619 | xe_exec_queue_is_multi_queue(q)); | ||
| 620 | |||
| 621 | /* Group banned, skip timeout check in TDR */ | ||
| 622 | WRITE_ONCE(group->banned, true); | ||
| 623 | xe_guc_exec_queue_trigger_cleanup(primary); | ||
| 624 | |||
| 625 | mutex_lock(&group->list_lock); | ||
| 626 | list_for_each_entry(eq, &group->list, multi_queue.link) | ||
| 627 | xe_guc_exec_queue_trigger_cleanup(eq); | ||
| 628 | mutex_unlock(&group->list_lock); | ||
| 629 | } | ||
| 630 | |||
| 631 | static void xe_guc_exec_queue_reset_trigger_cleanup(struct xe_exec_queue *q) | ||
| 632 | { | ||
| 633 | if (xe_exec_queue_is_multi_queue(q)) { | ||
| 634 | struct xe_exec_queue *primary = xe_exec_queue_multi_queue_primary(q); | ||
| 635 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 636 | struct xe_exec_queue *eq; | ||
| 637 | |||
| 638 | /* Group banned, skip timeout check in TDR */ | ||
| 639 | WRITE_ONCE(group->banned, true); | ||
| 640 | |||
| 641 | set_exec_queue_reset(primary); | ||
| 642 | if (!exec_queue_banned(primary) && !exec_queue_check_timeout(primary)) | ||
| 643 | xe_guc_exec_queue_trigger_cleanup(primary); | ||
| 644 | |||
| 645 | mutex_lock(&group->list_lock); | ||
| 646 | list_for_each_entry(eq, &group->list, multi_queue.link) { | ||
| 647 | set_exec_queue_reset(eq); | ||
| 648 | if (!exec_queue_banned(eq) && !exec_queue_check_timeout(eq)) | ||
| 649 | xe_guc_exec_queue_trigger_cleanup(eq); | ||
| 650 | } | ||
| 651 | mutex_unlock(&group->list_lock); | ||
| 652 | } else { | ||
| 653 | set_exec_queue_reset(q); | ||
| 654 | if (!exec_queue_banned(q) && !exec_queue_check_timeout(q)) | ||
| 655 | xe_guc_exec_queue_trigger_cleanup(q); | ||
| 656 | } | ||
| 657 | } | ||
| 658 | |||
| 659 | static void set_exec_queue_group_banned(struct xe_exec_queue *q) | ||
| 660 | { | ||
| 661 | struct xe_exec_queue *primary = xe_exec_queue_multi_queue_primary(q); | ||
| 662 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 663 | struct xe_exec_queue *eq; | ||
| 664 | |||
| 665 | /* Ban all queues of the multi-queue group */ | ||
| 666 | xe_gt_assert(guc_to_gt(exec_queue_to_guc(q)), | ||
| 667 | xe_exec_queue_is_multi_queue(q)); | ||
| 668 | set_exec_queue_banned(primary); | ||
| 669 | |||
| 670 | mutex_lock(&group->list_lock); | ||
| 671 | list_for_each_entry(eq, &group->list, multi_queue.link) | ||
| 672 | set_exec_queue_banned(eq); | ||
| 673 | mutex_unlock(&group->list_lock); | ||
| 674 | } | ||
| 675 | |||
| 571 | #define parallel_read(xe_, map_, field_) \ | 676 | #define parallel_read(xe_, map_, field_) \ |
| 572 | xe_map_rd_field(xe_, &map_, 0, struct guc_submit_parallel_scratch, \ | 677 | xe_map_rd_field(xe_, &map_, 0, struct guc_submit_parallel_scratch, \ |
| 573 | field_) | 678 | field_) |
| @@ -575,6 +680,181 @@ static void set_min_preemption_timeout(struct xe_guc *guc, struct xe_exec_queue · 1 unmodified line | |||
| 575 | xe_map_wr_field(xe_, &map_, 0, struct guc_submit_parallel_scratch, \ | 680 | xe_map_wr_field(xe_, &map_, 0, struct guc_submit_parallel_scratch, \ |
| 576 | field_, val_) | 681 | field_, val_) |
| 577 | 682 | ||
| 683 | /** | ||
| 684 | * DOC: Multi Queue Group GuC interface | ||
| 685 | * | ||
| 686 | * The multi queue group coordination between KMD and GuC is through a software | ||
| 687 | * construct called Context Group Page (CGP). The CGP is a KMD managed 4KB page | ||
| 688 | * allocated in the global GTT. | ||
| 689 | * | ||
| 690 | * CGP format: | ||
| 691 | * | ||
| 692 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 693 | * | DWORD | Name | Description | | ||
| 694 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 695 | * | 0 | Version | Bits [15:8]=Major ver, [7:0]=Minor ver | | ||
| 696 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 697 | * | 1..15 | RESERVED | MBZ | | ||
| 698 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 699 | * | 16 | KMD_QUEUE_UPDATE_MASK_DW0 | KMD queue mask for queues 31..0 | | ||
| 700 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 701 | * | 17 | KMD_QUEUE_UPDATE_MASK_DW1 | KMD queue mask for queues 63..32 | | ||
| 702 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 703 | * | 18..31 | RESERVED | MBZ | | ||
| 704 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 705 | * | 32 | Q0CD_DW0 | Queue 0 context LRC descriptor lower DWORD | | ||
| 706 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 707 | * | 33 | Q0ContextIndex | Context ID for Queue 0 | | ||
| 708 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 709 | * | 34 | Q1CD_DW0 | Queue 1 context LRC descriptor lower DWORD | | ||
| 710 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 711 | * | 35 | Q1ContextIndex | Context ID for Queue 1 | | ||
| 712 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 713 | * | ... |... | ... | | ||
| 714 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 715 | * | 158 | Q63CD_DW0 | Queue 63 context LRC descriptor lower DWORD | | ||
| 716 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 717 | * | 159 | Q63ContextIndex | Context ID for Queue 63 | | ||
| 718 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 719 | * | 160..1024 | RESERVED | MBZ | | ||
| 720 | * +-----------+---------------------------+---------------------------------------------+ | ||
| 721 | * | ||
| 722 | * While registering Q0 with GuC, CGP is updated with Q0 entry and GuC is notified | ||
| 723 | * through XE_GUC_ACTION_REGISTER_CONTEXT_MULTI_QUEUE H2G message which specifies | ||
| 724 | * the CGP address. When the secondary queues are added to the group, the CGP is | ||
| 725 | * updated with entry for that queue and GuC is notified through the H2G interface | ||
| 726 | * XE_GUC_ACTION_MULTI_QUEUE_CONTEXT_CGP_SYNC. GuC responds to these H2G messages | ||
| 727 | * with a XE_GUC_ACTION_NOTIFY_MULTIQ_CONTEXT_CGP_SYNC_DONE G2H message. GuC also | ||
| 728 | * sends a XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CGP_CONTEXT_ERROR notification for any | ||
| 729 | * error in the CGP. Only one of these CGP update messages can be outstanding | ||
| 730 | * (waiting for GuC response) at any time. The bits in KMD_QUEUE_UPDATE_MASK_DW* | ||
| 731 | * fields indicate which queue entry is being updated in the CGP. | ||
| 732 | * | ||
| 733 | * The primary queue (Q0) represents the multi queue group context in GuC and | ||
| 734 | * submission on any queue of the group must be through Q0 GuC interface only. | ||
| 735 | * | ||
| 736 | * As it is not required to register secondary queues with GuC, the secondary queue | ||
| 737 | * context ids in the CGP are populated with Q0 context id. | ||
| 738 | */ | ||
| 739 | |||
| 740 | #define CGP_VERSION_MAJOR_SHIFT 8 | ||
| 741 | |||
| 742 | static void xe_guc_exec_queue_group_cgp_update(struct xe_device *xe, | ||
| 743 | struct xe_exec_queue *q) | ||
| 744 | { | ||
| 745 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 746 | u32 guc_id = group->primary->guc->id; | ||
| 747 | |||
| 748 | /* Currently implementing CGP version 1.0 */ | ||
| 749 | xe_map_wr(xe, &group->cgp_bo->vmap, 0, u32, | ||
| 750 | 1 << CGP_VERSION_MAJOR_SHIFT); | ||
| 751 | |||
| 752 | xe_map_wr(xe, &group->cgp_bo->vmap, | ||
| 753 | (32 + q->multi_queue.pos * 2) * sizeof(u32), | ||
| 754 | u32, lower_32_bits(xe_lrc_descriptor(q->lrc[0]))); | ||
| 755 | |||
| 756 | xe_map_wr(xe, &group->cgp_bo->vmap, | ||
| 757 | (33 + q->multi_queue.pos * 2) * sizeof(u32), | ||
| 758 | u32, guc_id); | ||
| 759 | |||
| 760 | if (q->multi_queue.pos / 32) { | ||
| 761 | xe_map_wr(xe, &group->cgp_bo->vmap, 17 * sizeof(u32), | ||
| 762 | u32, BIT(q->multi_queue.pos % 32)); | ||
| 763 | xe_map_wr(xe, &group->cgp_bo->vmap, 16 * sizeof(u32), u32, 0); | ||
| 764 | } else { | ||
| 765 | xe_map_wr(xe, &group->cgp_bo->vmap, 16 * sizeof(u32), | ||
| 766 | u32, BIT(q->multi_queue.pos)); | ||
| 767 | xe_map_wr(xe, &group->cgp_bo->vmap, 17 * sizeof(u32), u32, 0); | ||
| 768 | } | ||
| 769 | } | ||
| 770 | |||
| 771 | static void xe_guc_exec_queue_group_cgp_sync(struct xe_guc *guc, | ||
| 772 | struct xe_exec_queue *q, | ||
| 773 | const u32 *action, u32 len) | ||
| 774 | { | ||
| 775 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 776 | struct xe_device *xe = guc_to_xe(guc); | ||
| 777 | long ret; | ||
| 778 | |||
| 779 | /* | ||
| 780 | * As all queues of a multi queue group use single drm scheduler | ||
| 781 | * submit workqueue, CGP synchronization with GuC are serialized. | ||
| 782 | * Hence, no locking is required here. | ||
| 783 | * Wait for any pending CGP_SYNC_DONE response before updating the | ||
| 784 | * CGP page and sending CGP_SYNC message. | ||
| 785 | * | ||
| 786 | * FIXME: Support VF migration | ||
| 787 | */ | ||
| 788 | ret = wait_event_timeout(guc->ct.wq, | ||
| 789 | !READ_ONCE(group->sync_pending) || | ||
| 790 | xe_guc_read_stopped(guc), HZ); | ||
| 791 | if (!ret || xe_guc_read_stopped(guc)) { | ||
| 792 | /* CGP_SYNC failed. Reset gt, cleanup the group */ | ||
| 793 | xe_gt_warn(guc_to_gt(guc), "Wait for CGP_SYNC_DONE response failed!\n"); | ||
| 794 | set_exec_queue_group_banned(q); | ||
| 795 | xe_gt_reset_async(q->gt); | ||
| 796 | xe_guc_exec_queue_group_trigger_cleanup(q); | ||
| 797 | return; | ||
| 798 | } | ||
| 799 | |||
| 800 | xe_lrc_set_multi_queue_priority(q->lrc[0], q->multi_queue.priority); | ||
| 801 | xe_guc_exec_queue_group_cgp_update(xe, q); | ||
| 802 | |||
| 803 | WRITE_ONCE(group->sync_pending, true); | ||
| 804 | xe_guc_ct_send(&guc->ct, action, len, G2H_LEN_DW_MULTI_QUEUE_CONTEXT, 1); | ||
| 805 | } | ||
| 806 | |||
| 807 | static void __register_exec_queue_group(struct xe_guc *guc, | ||
| 808 | struct xe_exec_queue *q, | ||
| 809 | struct guc_ctxt_registration_info *info) | ||
| 810 | { | ||
| 811 | #define MAX_MULTI_QUEUE_REG_SIZE (8) | ||
| 812 | u32 action[MAX_MULTI_QUEUE_REG_SIZE]; | ||
| 813 | int len = 0; | ||
| 814 | |||
| 815 | action[len++] = XE_GUC_ACTION_REGISTER_CONTEXT_MULTI_QUEUE; | ||
| 816 | action[len++] = info->flags; | ||
| 817 | action[len++] = info->context_idx; | ||
| 818 | action[len++] = info->engine_class; | ||
| 819 | action[len++] = info->engine_submit_mask; | ||
| 820 | action[len++] = 0; /* Reserved */ | ||
| 821 | action[len++] = info->cgp_lo; | ||
| 822 | action[len++] = info->cgp_hi; | ||
| 823 | |||
| 824 | xe_gt_assert(guc_to_gt(guc), len <= MAX_MULTI_QUEUE_REG_SIZE); | ||
| 825 | #undef MAX_MULTI_QUEUE_REG_SIZE | ||
| 826 | |||
| 827 | /* | ||
| 828 | * The above XE_GUC_ACTION_REGISTER_CONTEXT_MULTI_QUEUE do expect a | ||
| 829 | * XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CONTEXT_CGP_SYNC_DONE response | ||
| 830 | * from guc. | ||
| 831 | */ | ||
| 832 | xe_guc_exec_queue_group_cgp_sync(guc, q, action, len); | ||
| 833 | } | ||
| 834 | |||
| 835 | static void xe_guc_exec_queue_group_add(struct xe_guc *guc, | ||
| 836 | struct xe_exec_queue *q) | ||
| 837 | { | ||
| 838 | #define MAX_MULTI_QUEUE_CGP_SYNC_SIZE (2) | ||
| 839 | u32 action[MAX_MULTI_QUEUE_CGP_SYNC_SIZE]; | ||
| 840 | int len = 0; | ||
| 841 | |||
| 842 | xe_gt_assert(guc_to_gt(guc), xe_exec_queue_is_multi_queue_secondary(q)); | ||
| 843 | |||
| 844 | action[len++] = XE_GUC_ACTION_MULTI_QUEUE_CONTEXT_CGP_SYNC; | ||
| 845 | action[len++] = q->multi_queue.group->primary->guc->id; | ||
| 846 | |||
| 847 | xe_gt_assert(guc_to_gt(guc), len <= MAX_MULTI_QUEUE_CGP_SYNC_SIZE); | ||
| 848 | #undef MAX_MULTI_QUEUE_CGP_SYNC_SIZE | ||
| 849 | |||
| 850 | /* | ||
| 851 | * The above XE_GUC_ACTION_MULTI_QUEUE_CONTEXT_CGP_SYNC do expect a | ||
| 852 | * XE_GUC_ACTION_NOTIFY_MULTI_QUEUE_CONTEXT_CGP_SYNC_DONE response | ||
| 853 | * from guc. | ||
| 854 | */ | ||
| 855 | xe_guc_exec_queue_group_cgp_sync(guc, q, action, len); | ||
| 856 | } | ||
| 857 | |||
| 578 | static void __register_mlrc_exec_queue(struct xe_guc *guc, | 858 | static void __register_mlrc_exec_queue(struct xe_guc *guc, |
| 579 | struct xe_exec_queue *q, | 859 | struct xe_exec_queue *q, |
| 580 | struct guc_ctxt_registration_info *info) | 860 | struct guc_ctxt_registration_info *info) |
| @@ -670,6 +950,13 @@ static void register_exec_queue(struct xe_exec_queue *q, int ctx_type) · 89 unmodified lines | |||
| 670 | info.flags = CONTEXT_REGISTRATION_FLAG_KMD | | 950 | info.flags = CONTEXT_REGISTRATION_FLAG_KMD | |
| 671 | FIELD_PREP(CONTEXT_REGISTRATION_FLAG_TYPE, ctx_type); | 951 | FIELD_PREP(CONTEXT_REGISTRATION_FLAG_TYPE, ctx_type); |
| 672 | 952 | ||
| 953 | if (xe_exec_queue_is_multi_queue(q)) { | ||
| 954 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 955 | |||
| 956 | info.cgp_lo = xe_bo_ggtt_addr(group->cgp_bo); | ||
| 957 | info.cgp_hi = 0; | ||
| 958 | } | ||
| 959 | |||
| 673 | if (xe_exec_queue_is_parallel(q)) { | 960 | if (xe_exec_queue_is_parallel(q)) { |
| 674 | u64 ggtt_addr = xe_lrc_parallel_ggtt_addr(lrc); | 961 | u64 ggtt_addr = xe_lrc_parallel_ggtt_addr(lrc); |
| 675 | struct iosys_map map = xe_lrc_parallel_map(lrc); | 962 | struct iosys_map map = xe_lrc_parallel_map(lrc); |
| @@ -700,11 +987,18 @@ static void register_exec_queue(struct xe_exec_queue *q, int ctx_type) · 24 unmodified lines | |||
| 700 | 987 | ||
| 701 | set_exec_queue_registered(q); | 988 | set_exec_queue_registered(q); |
| 702 | trace_xe_exec_queue_register(q); | 989 | trace_xe_exec_queue_register(q); |
| 703 | if (xe_exec_queue_is_parallel(q)) | 990 | if (xe_exec_queue_is_multi_queue_primary(q)) |
| 991 | __register_exec_queue_group(guc, q, &info); | ||
| 992 | else if (xe_exec_queue_is_parallel(q)) | ||
| 704 | __register_mlrc_exec_queue(guc, q, &info); | 993 | __register_mlrc_exec_queue(guc, q, &info); |
| 705 | else | 994 | else if (!xe_exec_queue_is_multi_queue_secondary(q)) |
| 706 | __register_exec_queue(guc, &info); | 995 | __register_exec_queue(guc, &info); |
| 707 | init_policies(guc, q); | 996 | |
| 997 | if (!xe_exec_queue_is_multi_queue_secondary(q)) | ||
| 998 | init_policies(guc, q); | ||
| 999 | |||
| 1000 | if (xe_exec_queue_is_multi_queue_secondary(q)) | ||
| 1001 | xe_guc_exec_queue_group_add(guc, q); | ||
| 708 | } | 1002 | } |
| 709 | 1003 | ||
| 710 | static u32 wq_space_until_wrap(struct xe_exec_queue *q) | 1004 | static u32 wq_space_until_wrap(struct xe_exec_queue *q) |
| @@ -712,11 +1006,6 @@ static u32 wq_space_until_wrap(struct xe_exec_queue *q) · 1 unmodified line | |||
| 712 | return (WQ_SIZE - q->guc->wqi_tail); | 1006 | return (WQ_SIZE - q->guc->wqi_tail); |
| 713 | } | 1007 | } |
| 714 | 1008 | ||
| 715 | static bool vf_recovery(struct xe_guc *guc) | ||
| 716 | { | ||
| 717 | return xe_gt_recovery_pending(guc_to_gt(guc)); | ||
| 718 | } | ||
| 719 | |||
| 720 | static inline void relaxed_ms_sleep(unsigned int delay_ms) | 1009 | static inline void relaxed_ms_sleep(unsigned int delay_ms) |
| 721 | { | 1010 | { |
| 722 | unsigned long min_us, max_us; | 1011 | unsigned long min_us, max_us; |
| @@ -845,7 +1134,7 @@ static void submit_exec_queue(struct xe_exec_queue *q, struct xe_sched_job *job) · 122 unmodified lines | |||
| 845 | if (!job->restore_replay || job->last_replay) { | 1134 | if (!job->restore_replay || job->last_replay) { |
| 846 | if (xe_exec_queue_is_parallel(q)) | 1135 | if (xe_exec_queue_is_parallel(q)) |
| 847 | wq_item_append(q); | 1136 | wq_item_append(q); |
| 848 | else | 1137 | else if (!exec_queue_idle_skip_suspend(q)) |
| 849 | xe_lrc_set_ring_tail(lrc, lrc->ring.tail); | 1138 | xe_lrc_set_ring_tail(lrc, lrc->ring.tail); |
| 850 | job->last_replay = false; | 1139 | job->last_replay = false; |
| 851 | } | 1140 | } |
| @@ -853,6 +1142,12 @@ static void submit_exec_queue(struct xe_exec_queue *q, struct xe_sched_job *job) · 1 unmodified line | |||
| 853 | if (exec_queue_suspended(q) && !xe_exec_queue_is_parallel(q)) | 1142 | if (exec_queue_suspended(q) && !xe_exec_queue_is_parallel(q)) |
| 854 | return; | 1143 | return; |
| 855 | 1144 | ||
| 1145 | /* | ||
| 1146 | * All queues in a multi-queue group will use the primary queue | ||
| 1147 | * of the group to interface with GuC. | ||
| 1148 | */ | ||
| 1149 | q = xe_exec_queue_multi_queue_primary(q); | ||
| 1150 | |||
| 856 | if (!exec_queue_enabled(q) && !exec_queue_suspended(q)) { | 1151 | if (!exec_queue_enabled(q) && !exec_queue_suspended(q)) { |
| 857 | action[len++] = XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET; | 1152 | action[len++] = XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET; |
| 858 | action[len++] = q->guc->id; | 1153 | action[len++] = q->guc->id; |
| @@ -899,6 +1194,18 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job) · 40 unmodified lines | |||
| 899 | trace_xe_sched_job_run(job); | 1194 | trace_xe_sched_job_run(job); |
| 900 | 1195 | ||
| 901 | if (!killed_or_banned_or_wedged && !xe_sched_job_is_error(job)) { | 1196 | if (!killed_or_banned_or_wedged && !xe_sched_job_is_error(job)) { |
| 1197 | if (xe_exec_queue_is_multi_queue_secondary(q)) { | ||
| 1198 | struct xe_exec_queue *primary = xe_exec_queue_multi_queue_primary(q); | ||
| 1199 | |||
| 1200 | if (exec_queue_killed_or_banned_or_wedged(primary)) { | ||
| 1201 | killed_or_banned_or_wedged = true; | ||
| 1202 | goto run_job_out; | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | if (!exec_queue_registered(primary)) | ||
| 1206 | register_exec_queue(primary, GUC_CONTEXT_NORMAL); | ||
| 1207 | } | ||
| 1208 | |||
| 902 | if (!exec_queue_registered(q)) | 1209 | if (!exec_queue_registered(q)) |
| 903 | register_exec_queue(q, GUC_CONTEXT_NORMAL); | 1210 | register_exec_queue(q, GUC_CONTEXT_NORMAL); |
| 904 | if (!job->restore_replay) | 1211 | if (!job->restore_replay) |
| @@ -907,6 +1214,7 @@ guc_exec_queue_run_job(struct drm_sched_job *drm_job) · 2 unmodified lines | |||
| 907 | job->restore_replay = false; | 1214 | job->restore_replay = false; |
| 908 | } | 1215 | } |
| 909 | 1216 | ||
| 1217 | run_job_out: | ||
| 910 | /* | 1218 | /* |
| 911 | * We don't care about job-fence ordering in LR VMs because these fences | 1219 | * We don't care about job-fence ordering in LR VMs because these fences |
| 912 | * are never exported; they are used solely to keep jobs on the pending | 1220 | * are never exported; they are used solely to keep jobs on the pending |
| @@ -932,6 +1240,11 @@ int xe_guc_read_stopped(struct xe_guc *guc) · 19 unmodified lines | |||
| 932 | return atomic_read(&guc->submission_state.stopped); | 1240 | return atomic_read(&guc->submission_state.stopped); |
| 933 | } | 1241 | } |
| 934 | 1242 | ||
| 1243 | static void handle_multi_queue_secondary_sched_done(struct xe_guc *guc, | ||
| 1244 | struct xe_exec_queue *q, | ||
| 1245 | u32 runnable_state); | ||
| 1246 | static void handle_deregister_done(struct xe_guc *guc, struct xe_exec_queue *q); | ||
| 1247 | |||
| 935 | #define MAKE_SCHED_CONTEXT_ACTION(q, enable_disable) \ | 1248 | #define MAKE_SCHED_CONTEXT_ACTION(q, enable_disable) \ |
| 936 | u32 action[] = { \ | 1249 | u32 action[] = { \ |
| 937 | XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET, \ | 1250 | XE_GUC_ACTION_SCHED_CONTEXT_MODE_SET, \ |
| @@ -945,7 +1258,9 @@ static void disable_scheduling_deregister(struct xe_guc *guc, · 7 unmodified lines | |||
| 945 | MAKE_SCHED_CONTEXT_ACTION(q, DISABLE); | 1258 | MAKE_SCHED_CONTEXT_ACTION(q, DISABLE); |
| 946 | int ret; | 1259 | int ret; |
| 947 | 1260 | ||
| 948 | set_min_preemption_timeout(guc, q); | 1261 | if (!xe_exec_queue_is_multi_queue_secondary(q)) |
| 1262 | set_min_preemption_timeout(guc, q); | ||
| 1263 | |||
| 949 | smp_rmb(); | 1264 | smp_rmb(); |
| 950 | ret = wait_event_timeout(guc->ct.wq, | 1265 | ret = wait_event_timeout(guc->ct.wq, |
| 951 | (!exec_queue_pending_enable(q) && | 1266 | (!exec_queue_pending_enable(q) && |
| @@ -973,23 +1288,12 @@ static void disable_scheduling_deregister(struct xe_guc *guc, · 21 unmodified lines | |||
| 973 | * Reserve space for both G2H here as the 2nd G2H is sent from a G2H | 1288 | * Reserve space for both G2H here as the 2nd G2H is sent from a G2H |
| 974 | * handler and we are not allowed to reserved G2H space in handlers. | 1289 | * handler and we are not allowed to reserved G2H space in handlers. |
| 975 | */ | 1290 | */ |
| 976 | xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), | 1291 | if (xe_exec_queue_is_multi_queue_secondary(q)) |
| 977 | G2H_LEN_DW_SCHED_CONTEXT_MODE_SET + | 1292 | handle_multi_queue_secondary_sched_done(guc, q, 0); |
| 978 | G2H_LEN_DW_DEREGISTER_CONTEXT, 2); | ||
| 979 | } | ||
| 980 | |||
| 981 | static void xe_guc_exec_queue_trigger_cleanup(struct xe_exec_queue *q) | ||
| 982 | { | ||
| 983 | struct xe_guc *guc = exec_queue_to_guc(q); | ||
| 984 | struct xe_device *xe = guc_to_xe(guc); | ||
| 985 | |||
| 986 | /** to wakeup xe_wait_user_fence ioctl if exec queue is reset */ | ||
| 987 | wake_up_all(&xe->ufence_wq); | ||
| 988 | |||
| 989 | if (xe_exec_queue_is_lr(q)) | ||
| 990 | queue_work(guc_to_gt(guc)->ordered_wq, &q->guc->lr_tdr); | ||
| 991 | else | 1293 | else |
| 992 | xe_sched_tdr_queue_imm(&q->guc->sched); | 1294 | xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), |
| 1295 | G2H_LEN_DW_SCHED_CONTEXT_MODE_SET + | ||
| 1296 | G2H_LEN_DW_DEREGISTER_CONTEXT, 2); | ||
| 993 | } | 1297 | } |
| 994 | 1298 | ||
| 995 | /** | 1299 | /** |
| @@ -1181,8 +1485,11 @@ static void enable_scheduling(struct xe_exec_queue *q) · 185 unmodified lines | |||
| 1181 | set_exec_queue_enabled(q); | 1485 | set_exec_queue_enabled(q); |
| 1182 | trace_xe_exec_queue_scheduling_enable(q); | 1486 | trace_xe_exec_queue_scheduling_enable(q); |
| 1183 | 1487 | ||
| 1184 | xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), | 1488 | if (xe_exec_queue_is_multi_queue_secondary(q)) |
| 1185 | G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, 1); | 1489 | handle_multi_queue_secondary_sched_done(guc, q, 1); |
| 1490 | else | ||
| 1491 | xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), | ||
| 1492 | G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, 1); | ||
| 1186 | 1493 | ||
| 1187 | ret = wait_event_timeout(guc->ct.wq, | 1494 | ret = wait_event_timeout(guc->ct.wq, |
| 1188 | !exec_queue_pending_enable(q) || | 1495 | !exec_queue_pending_enable(q) || |
| @@ -1206,14 +1513,17 @@ static void disable_scheduling(struct xe_exec_queue *q, bool immediate) · 17 unmodified lines | |||
| 1206 | xe_gt_assert(guc_to_gt(guc), exec_queue_registered(q)); | 1513 | xe_gt_assert(guc_to_gt(guc), exec_queue_registered(q)); |
| 1207 | xe_gt_assert(guc_to_gt(guc), !exec_queue_pending_disable(q)); | 1514 | xe_gt_assert(guc_to_gt(guc), !exec_queue_pending_disable(q)); |
| 1208 | 1515 | ||
| 1209 | if (immediate) | 1516 | if (immediate && !xe_exec_queue_is_multi_queue_secondary(q)) |
| 1210 | set_min_preemption_timeout(guc, q); | 1517 | set_min_preemption_timeout(guc, q); |
| 1211 | clear_exec_queue_enabled(q); | 1518 | clear_exec_queue_enabled(q); |
| 1212 | set_exec_queue_pending_disable(q); | 1519 | set_exec_queue_pending_disable(q); |
| 1213 | trace_xe_exec_queue_scheduling_disable(q); | 1520 | trace_xe_exec_queue_scheduling_disable(q); |
| 1214 | 1521 | ||
| 1215 | xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), | 1522 | if (xe_exec_queue_is_multi_queue_secondary(q)) |
| 1216 | G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, 1); | 1523 | handle_multi_queue_secondary_sched_done(guc, q, 0); |
| 1524 | else | ||
| 1525 | xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), | ||
| 1526 | G2H_LEN_DW_SCHED_CONTEXT_MODE_SET, 1); | ||
| 1217 | } | 1527 | } |
| 1218 | 1528 | ||
| 1219 | static void __deregister_exec_queue(struct xe_guc *guc, struct xe_exec_queue *q) | 1529 | static void __deregister_exec_queue(struct xe_guc *guc, struct xe_exec_queue *q) |
| @@ -1231,8 +1541,11 @@ static void __deregister_exec_queue(struct xe_guc *guc, struct xe_exec_queue *q) · 11 unmodified lines | |||
| 1231 | set_exec_queue_destroyed(q); | 1541 | set_exec_queue_destroyed(q); |
| 1232 | trace_xe_exec_queue_deregister(q); | 1542 | trace_xe_exec_queue_deregister(q); |
| 1233 | 1543 | ||
| 1234 | xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), | 1544 | if (xe_exec_queue_is_multi_queue_secondary(q)) |
| 1235 | G2H_LEN_DW_DEREGISTER_CONTEXT, 1); | 1545 | handle_deregister_done(guc, q); |
| 1546 | else | ||
| 1547 | xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), | ||
| 1548 | G2H_LEN_DW_DEREGISTER_CONTEXT, 1); | ||
| 1236 | } | 1549 | } |
| 1237 | 1550 | ||
| 1238 | static enum drm_gpu_sched_stat | 1551 | static enum drm_gpu_sched_stat |
| @@ -1245,7 +1558,6 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) · 6 unmodified lines | |||
| 1245 | struct xe_guc *guc = exec_queue_to_guc(q); | 1558 | struct xe_guc *guc = exec_queue_to_guc(q); |
| 1246 | const char *process_name = "no process"; | 1559 | const char *process_name = "no process"; |
| 1247 | struct xe_device *xe = guc_to_xe(guc); | 1560 | struct xe_device *xe = guc_to_xe(guc); |
| 1248 | unsigned int fw_ref; | ||
| 1249 | int err = -ETIME; | 1561 | int err = -ETIME; |
| 1250 | pid_t pid = -1; | 1562 | pid_t pid = -1; |
| 1251 | int i = 0; | 1563 | int i = 0; |
| @@ -1271,6 +1583,19 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) · 19 unmodified lines | |||
| 1271 | exec_queue_killed_or_banned_or_wedged(q) || | 1583 | exec_queue_killed_or_banned_or_wedged(q) || |
| 1272 | exec_queue_destroyed(q); | 1584 | exec_queue_destroyed(q); |
| 1273 | 1585 | ||
| 1586 | /* Skip timeout check if multi-queue group is banned */ | ||
| 1587 | if (xe_exec_queue_is_multi_queue(q) && | ||
| 1588 | READ_ONCE(q->multi_queue.group->banned)) | ||
| 1589 | skip_timeout_check = true; | ||
| 1590 | |||
| 1591 | /* | ||
| 1592 | * FIXME: In multi-queue scenario, the TDR must ensure that the whole | ||
| 1593 | * multi-queue group is off the HW before signaling the fences to avoid | ||
| 1594 | * possible memory corruptions. This means disabling scheduling on the | ||
| 1595 | * primary queue before or during the secondary queue's TDR. Need to | ||
| 1596 | * implement this in least obtrusive way. | ||
| 1597 | */ | ||
| 1598 | |||
| 1274 | /* | 1599 | /* |
| 1275 | * If devcoredump not captured and GuC capture for the job is not ready | 1600 | * If devcoredump not captured and GuC capture for the job is not ready |
| 1276 | * do manual capture first and decide later if we need to use it | 1601 | * do manual capture first and decide later if we need to use it |
| @@ -1278,13 +1603,11 @@ guc_exec_queue_timedout_job(struct drm_sched_job *drm_job) · 1 unmodified line | |||
| 1278 | if (!exec_queue_killed(q) && !xe->devcoredump.captured && | 1603 | if (!exec_queue_killed(q) && !xe->devcoredump.captured && |
| 1279 | !xe_guc_capture_get_matching_and_lock(q)) { | 1604 | !xe_guc_capture_get_matching_and_lock(q)) { |
| 1280 | /* take force wake before engine register manual capture */ | 1605 | /* take force wake before engine register manual capture */ |
| 1281 | fw_ref = xe_force_wake_get(gt_to_fw(q->gt), XE_FORCEWAKE_ALL); | 1606 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(q->gt), XE_FORCEWAKE_ALL); |
| 1282 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) | 1607 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) |
| 1283 | xe_gt_info(q->gt, "failed to get forcewake for coredump capture\n"); | 1608 | xe_gt_info(q->gt, "failed to get forcewake for coredump capture\n"); |
| 1284 | 1609 | ||
| 1285 | xe_engine_snapshot_capture_for_queue(q); | 1610 | xe_engine_snapshot_capture_for_queue(q); |
| 1286 | |||
| 1287 | xe_force_wake_put(gt_to_fw(q->gt), fw_ref); | ||
| 1288 | } | 1611 | } |
| 1289 | 1612 | ||
| 1290 | /* | 1613 | /* |
| @@ -1425,7 +1748,10 @@ trigger_reset: · 134 unmodified lines | |||
| 1425 | xe_sched_add_pending_job(sched, job); | 1748 | xe_sched_add_pending_job(sched, job); |
| 1426 | xe_sched_submission_start(sched); | 1749 | xe_sched_submission_start(sched); |
| 1427 | 1750 | ||
| 1428 | xe_guc_exec_queue_trigger_cleanup(q); | 1751 | if (xe_exec_queue_is_multi_queue(q)) |
| 1752 | xe_guc_exec_queue_group_trigger_cleanup(q); | ||
| 1753 | else | ||
| 1754 | xe_guc_exec_queue_trigger_cleanup(q); | ||
| 1429 | 1755 | ||
| 1430 | /* Mark all outstanding jobs as bad, thus completing them */ | 1756 | /* Mark all outstanding jobs as bad, thus completing them */ |
| 1431 | spin_lock(&sched->base.job_list_lock); | 1757 | spin_lock(&sched->base.job_list_lock); |
| @@ -1475,17 +1801,23 @@ static void __guc_exec_queue_destroy_async(struct work_struct *w) · 43 unmodified lines | |||
| 1475 | struct xe_exec_queue *q = ge->q; | 1801 | struct xe_exec_queue *q = ge->q; |
| 1476 | struct xe_guc *guc = exec_queue_to_guc(q); | 1802 | struct xe_guc *guc = exec_queue_to_guc(q); |
| 1477 | 1803 | ||
| 1478 | xe_pm_runtime_get(guc_to_xe(guc)); | 1804 | guard(xe_pm_runtime)(guc_to_xe(guc)); |
| 1479 | trace_xe_exec_queue_destroy(q); | 1805 | trace_xe_exec_queue_destroy(q); |
| 1480 | 1806 | ||
| 1807 | if (xe_exec_queue_is_multi_queue_secondary(q)) { | ||
| 1808 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 1809 | |||
| 1810 | mutex_lock(&group->list_lock); | ||
| 1811 | list_del(&q->multi_queue.link); | ||
| 1812 | mutex_unlock(&group->list_lock); | ||
| 1813 | } | ||
| 1814 | |||
| 1481 | if (xe_exec_queue_is_lr(q)) | 1815 | if (xe_exec_queue_is_lr(q)) |
| 1482 | cancel_work_sync(&ge->lr_tdr); | 1816 | cancel_work_sync(&ge->lr_tdr); |
| 1483 | /* Confirm no work left behind accessing device structures */ | 1817 | /* Confirm no work left behind accessing device structures */ |
| 1484 | cancel_delayed_work_sync(&ge->sched.base.work_tdr); | 1818 | cancel_delayed_work_sync(&ge->sched.base.work_tdr); |
| 1485 | 1819 | ||
| 1486 | xe_exec_queue_fini(q); | 1820 | xe_exec_queue_fini(q); |
| 1487 | |||
| 1488 | xe_pm_runtime_put(guc_to_xe(guc)); | ||
| 1489 | } | 1821 | } |
| 1490 | 1822 | ||
| 1491 | static void guc_exec_queue_destroy_async(struct xe_exec_queue *q) | 1823 | static void guc_exec_queue_destroy_async(struct xe_exec_queue *q) |
| @@ -1590,9 +1922,10 @@ static void __guc_exec_queue_process_msg_suspend(struct xe_sched_msg *msg) · 98 unmodified lines | |||
| 1590 | { | 1922 | { |
| 1591 | struct xe_exec_queue *q = msg->private_data; | 1923 | struct xe_exec_queue *q = msg->private_data; |
| 1592 | struct xe_guc *guc = exec_queue_to_guc(q); | 1924 | struct xe_guc *guc = exec_queue_to_guc(q); |
| 1925 | bool idle_skip_suspend = xe_exec_queue_idle_skip_suspend(q); | ||
| 1593 | 1926 | ||
| 1594 | if (guc_exec_queue_allowed_to_change_state(q) && !exec_queue_suspended(q) && | 1927 | if (!idle_skip_suspend && guc_exec_queue_allowed_to_change_state(q) && |
| 1595 | exec_queue_enabled(q)) { | 1928 | !exec_queue_suspended(q) && exec_queue_enabled(q)) { |
| 1596 | wait_event(guc->ct.wq, vf_recovery(guc) || | 1929 | wait_event(guc->ct.wq, vf_recovery(guc) || |
| 1597 | ((q->guc->resume_time != RESUME_PENDING || | 1930 | ((q->guc->resume_time != RESUME_PENDING || |
| 1598 | xe_guc_read_stopped(guc)) && !exec_queue_pending_disable(q))); | 1931 | xe_guc_read_stopped(guc)) && !exec_queue_pending_disable(q))); |
| @@ -1611,11 +1944,33 @@ static void __guc_exec_queue_process_msg_suspend(struct xe_sched_msg *msg) · 12 unmodified lines | |||
| 1611 | disable_scheduling(q, false); | 1944 | disable_scheduling(q, false); |
| 1612 | } | 1945 | } |
| 1613 | } else if (q->guc->suspend_pending) { | 1946 | } else if (q->guc->suspend_pending) { |
| 1947 | if (idle_skip_suspend) | ||
| 1948 | set_exec_queue_idle_skip_suspend(q); | ||
| 1614 | set_exec_queue_suspended(q); | 1949 | set_exec_queue_suspended(q); |
| 1615 | suspend_fence_signal(q); | 1950 | suspend_fence_signal(q); |
| 1616 | } | 1951 | } |
| 1617 | } | 1952 | } |
| 1618 | 1953 | ||
| 1954 | static void sched_context(struct xe_exec_queue *q) | ||
| 1955 | { | ||
| 1956 | struct xe_guc *guc = exec_queue_to_guc(q); | ||
| 1957 | struct xe_lrc *lrc = q->lrc[0]; | ||
| 1958 | u32 action[] = { | ||
| 1959 | XE_GUC_ACTION_SCHED_CONTEXT, | ||
| 1960 | q->guc->id, | ||
| 1961 | }; | ||
| 1962 | |||
| 1963 | xe_gt_assert(guc_to_gt(guc), !xe_exec_queue_is_parallel(q)); | ||
| 1964 | xe_gt_assert(guc_to_gt(guc), !exec_queue_destroyed(q)); | ||
| 1965 | xe_gt_assert(guc_to_gt(guc), exec_queue_registered(q)); | ||
| 1966 | xe_gt_assert(guc_to_gt(guc), !exec_queue_pending_disable(q)); | ||
| 1967 | |||
| 1968 | trace_xe_exec_queue_submit(q); | ||
| 1969 | |||
| 1970 | xe_lrc_set_ring_tail(lrc, lrc->ring.tail); | ||
| 1971 | xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), 0, 0); | ||
| 1972 | } | ||
| 1973 | |||
| 1619 | static void __guc_exec_queue_process_msg_resume(struct xe_sched_msg *msg) | 1974 | static void __guc_exec_queue_process_msg_resume(struct xe_sched_msg *msg) |
| 1620 | { | 1975 | { |
| 1621 | struct xe_exec_queue *q = msg->private_data; | 1976 | struct xe_exec_queue *q = msg->private_data; |
| @@ -1623,19 +1978,53 @@ static void __guc_exec_queue_process_msg_resume(struct xe_sched_msg *msg) · 1 unmodified line | |||
| 1623 | if (guc_exec_queue_allowed_to_change_state(q)) { | 1978 | if (guc_exec_queue_allowed_to_change_state(q)) { |
| 1624 | clear_exec_queue_suspended(q); | 1979 | clear_exec_queue_suspended(q); |
| 1625 | if (!exec_queue_enabled(q)) { | 1980 | if (!exec_queue_enabled(q)) { |
| 1981 | if (exec_queue_idle_skip_suspend(q)) { | ||
| 1982 | struct xe_lrc *lrc = q->lrc[0]; | ||
| 1983 | |||
| 1984 | clear_exec_queue_idle_skip_suspend(q); | ||
| 1985 | xe_lrc_set_ring_tail(lrc, lrc->ring.tail); | ||
| 1986 | } | ||
| 1626 | q->guc->resume_time = RESUME_PENDING; | 1987 | q->guc->resume_time = RESUME_PENDING; |
| 1627 | set_exec_queue_pending_resume(q); | 1988 | set_exec_queue_pending_resume(q); |
| 1628 | enable_scheduling(q); | 1989 | enable_scheduling(q); |
| 1990 | } else if (exec_queue_idle_skip_suspend(q)) { | ||
| 1991 | clear_exec_queue_idle_skip_suspend(q); | ||
| 1992 | sched_context(q); | ||
| 1629 | } | 1993 | } |
| 1630 | } else { | 1994 | } else { |
| 1631 | clear_exec_queue_suspended(q); | 1995 | clear_exec_queue_suspended(q); |
| 1996 | clear_exec_queue_idle_skip_suspend(q); | ||
| 1997 | } | ||
| 1998 | } | ||
| 1999 | |||
| 2000 | static void __guc_exec_queue_process_msg_set_multi_queue_priority(struct xe_sched_msg *msg) | ||
| 2001 | { | ||
| 2002 | struct xe_exec_queue *q = msg->private_data; | ||
| 2003 | |||
| 2004 | if (guc_exec_queue_allowed_to_change_state(q)) { | ||
| 2005 | #define MAX_MULTI_QUEUE_CGP_SYNC_SIZE (2) | ||
| 2006 | struct xe_guc *guc = exec_queue_to_guc(q); | ||
| 2007 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 2008 | u32 action[MAX_MULTI_QUEUE_CGP_SYNC_SIZE]; | ||
| 2009 | int len = 0; | ||
| 2010 | |||
| 2011 | action[len++] = XE_GUC_ACTION_MULTI_QUEUE_CONTEXT_CGP_SYNC; | ||
| 2012 | action[len++] = group->primary->guc->id; | ||
| 2013 | |||
| 2014 | xe_gt_assert(guc_to_gt(guc), len <= MAX_MULTI_QUEUE_CGP_SYNC_SIZE); | ||
| 2015 | #undef MAX_MULTI_QUEUE_CGP_SYNC_SIZE | ||
| 2016 | |||
| 2017 | xe_guc_exec_queue_group_cgp_sync(guc, q, action, len); | ||
| 1632 | } | 2018 | } |
| 2019 | |||
| 2020 | kfree(msg); | ||
| 1633 | } | 2021 | } |
| 1634 | 2022 | ||
| 1635 | #define CLEANUP 1 /* Non-zero values to catch uninitialized msg */ | 2023 | #define CLEANUP 1 /* Non-zero values to catch uninitialized msg */ |
| 1636 | #define SET_SCHED_PROPS 2 | 2024 | #define SET_SCHED_PROPS 2 |
| 1637 | #define SUSPEND 3 | 2025 | #define SUSPEND 3 |
| 1638 | #define RESUME 4 | 2026 | #define RESUME 4 |
| 2027 | #define SET_MULTI_QUEUE_PRIORITY 5 | ||
| 1639 | #define OPCODE_MASK 0xf | 2028 | #define OPCODE_MASK 0xf |
| 1640 | #define MSG_LOCKED BIT(8) | 2029 | #define MSG_LOCKED BIT(8) |
| 1641 | #define MSG_HEAD BIT(9) | 2030 | #define MSG_HEAD BIT(9) |
| @@ -1659,6 +2048,9 @@ static void guc_exec_queue_process_msg(struct xe_sched_msg *msg) · 17 unmodified lines | |||
| 1659 | case RESUME: | 2048 | case RESUME: |
| 1660 | __guc_exec_queue_process_msg_resume(msg); | 2049 | __guc_exec_queue_process_msg_resume(msg); |
| 1661 | break; | 2050 | break; |
| 2051 | case SET_MULTI_QUEUE_PRIORITY: | ||
| 2052 | __guc_exec_queue_process_msg_set_multi_queue_priority(msg); | ||
| 2053 | break; | ||
| 1662 | default: | 2054 | default: |
| 1663 | XE_WARN_ON("Unknown message type"); | 2055 | XE_WARN_ON("Unknown message type"); |
| 1664 | } | 2056 | } |
| @@ -1680,6 +2072,7 @@ static int guc_exec_queue_init(struct xe_exec_queue *q) · 15 unmodified lines | |||
| 1680 | { | 2072 | { |
| 1681 | struct xe_gpu_scheduler *sched; | 2073 | struct xe_gpu_scheduler *sched; |
| 1682 | struct xe_guc *guc = exec_queue_to_guc(q); | 2074 | struct xe_guc *guc = exec_queue_to_guc(q); |
| 2075 | struct workqueue_struct *submit_wq = NULL; | ||
| 1683 | struct xe_guc_exec_queue *ge; | 2076 | struct xe_guc_exec_queue *ge; |
| 1684 | long timeout; | 2077 | long timeout; |
| 1685 | int err, i; | 2078 | int err, i; |
| @@ -1700,8 +2093,20 @@ static int guc_exec_queue_init(struct xe_exec_queue *q) · 14 unmodified lines | |||
| 1700 | 2093 | ||
| 1701 | timeout = (q->vm && xe_vm_in_lr_mode(q->vm)) ? MAX_SCHEDULE_TIMEOUT : | 2094 | timeout = (q->vm && xe_vm_in_lr_mode(q->vm)) ? MAX_SCHEDULE_TIMEOUT : |
| 1702 | msecs_to_jiffies(q->sched_props.job_timeout_ms); | 2095 | msecs_to_jiffies(q->sched_props.job_timeout_ms); |
| 2096 | |||
| 2097 | /* | ||
| 2098 | * Use primary queue's submit_wq for all secondary queues of a | ||
| 2099 | * multi queue group. This serialization avoids any locking around | ||
| 2100 | * CGP synchronization with GuC. | ||
| 2101 | */ | ||
| 2102 | if (xe_exec_queue_is_multi_queue_secondary(q)) { | ||
| 2103 | struct xe_exec_queue *primary = xe_exec_queue_multi_queue_primary(q); | ||
| 2104 | |||
| 2105 | submit_wq = primary->guc->sched.base.submit_wq; | ||
| 2106 | } | ||
| 2107 | |||
| 1703 | err = xe_sched_init(&ge->sched, &drm_sched_ops, &xe_sched_ops, | 2108 | err = xe_sched_init(&ge->sched, &drm_sched_ops, &xe_sched_ops, |
| 1704 | NULL, xe_lrc_ring_size() / MAX_JOB_SIZE_BYTES, 64, | 2109 | submit_wq, xe_lrc_ring_size() / MAX_JOB_SIZE_BYTES, 64, |
| 1705 | timeout, guc_to_gt(guc)->ordered_wq, NULL, | 2110 | timeout, guc_to_gt(guc)->ordered_wq, NULL, |
| 1706 | q->name, gt_to_xe(q->gt)->drm.dev); | 2111 | q->name, gt_to_xe(q->gt)->drm.dev); |
| 1707 | if (err) | 2112 | if (err) |
| @@ -1730,7 +2135,23 @@ static int guc_exec_queue_init(struct xe_exec_queue *q) · 22 unmodified lines | |||
| 1730 | 2135 | ||
| 1731 | xe_exec_queue_assign_name(q, q->guc->id); | 2136 | xe_exec_queue_assign_name(q, q->guc->id); |
| 1732 | 2137 | ||
| 1733 | trace_xe_exec_queue_create(q); | 2138 | /* |
| 2139 | * Maintain secondary queues of the multi queue group in a list | ||
| 2140 | * for handling dependencies across the queues in the group. | ||
| 2141 | */ | ||
| 2142 | if (xe_exec_queue_is_multi_queue_secondary(q)) { | ||
| 2143 | struct xe_exec_queue_group *group = q->multi_queue.group; | ||
| 2144 | |||
| 2145 | INIT_LIST_HEAD(&q->multi_queue.link); | ||
| 2146 | mutex_lock(&group->list_lock); | ||
| 2147 | list_add_tail(&q->multi_queue.link, &group->list); | ||
| 2148 | mutex_unlock(&group->list_lock); | ||
| 2149 | } | ||
| 2150 | |||
| 2151 | if (xe_exec_queue_is_multi_queue(q)) | ||
| 2152 | trace_xe_exec_queue_create_multi_queue(q); | ||
| 2153 | else | ||
| 2154 | trace_xe_exec_queue_create(q); | ||
| 1734 | 2155 | ||
| 1735 | return 0; | 2156 | return 0; |
| 1736 | 2157 | ||
| @@ -1862,6 +2283,27 @@ static int guc_exec_queue_set_preempt_timeout(struct xe_exec_queue *q, · 125 unmodified lines | |||
| 1862 | return 0; | 2283 | return 0; |
| 1863 | } | 2284 | } |
| 1864 | 2285 | ||
| 2286 | static int guc_exec_queue_set_multi_queue_priority(struct xe_exec_queue *q, | ||
| 2287 | enum xe_multi_queue_priority priority) | ||
| 2288 | { | ||
| 2289 | struct xe_sched_msg *msg; | ||
| 2290 | |||
| 2291 | xe_gt_assert(guc_to_gt(exec_queue_to_guc(q)), xe_exec_queue_is_multi_queue(q)); | ||
| 2292 | |||
| 2293 | if (q->multi_queue.priority == priority || | ||
| 2294 | exec_queue_killed_or_banned_or_wedged(q)) | ||
| 2295 | return 0; | ||
| 2296 | |||
| 2297 | msg = kmalloc(sizeof(*msg), GFP_KERNEL); | ||
| 2298 | if (!msg) | ||
| 2299 | return -ENOMEM; | ||
| 2300 | |||
| 2301 | q->multi_queue.priority = priority; | ||
| 2302 | guc_exec_queue_add_msg(q, msg, SET_MULTI_QUEUE_PRIORITY); | ||
| 2303 | |||
| 2304 | return 0; | ||
| 2305 | } | ||
| 2306 | |||
| 1865 | static int guc_exec_queue_suspend(struct xe_exec_queue *q) | 2307 | static int guc_exec_queue_suspend(struct xe_exec_queue *q) |
| 1866 | { | 2308 | { |
| 1867 | struct xe_gpu_scheduler *sched = &q->guc->sched; | 2309 | struct xe_gpu_scheduler *sched = &q->guc->sched; |
| @@ -1936,6 +2378,10 @@ static void guc_exec_queue_resume(struct xe_exec_queue *q) · 68 unmodified lines | |||
| 1936 | 2378 | ||
| 1937 | static bool guc_exec_queue_reset_status(struct xe_exec_queue *q) | 2379 | static bool guc_exec_queue_reset_status(struct xe_exec_queue *q) |
| 1938 | { | 2380 | { |
| 2381 | if (xe_exec_queue_is_multi_queue_secondary(q) && | ||
| 2382 | guc_exec_queue_reset_status(xe_exec_queue_multi_queue_primary(q))) | ||
| 2383 | return true; | ||
| 2384 | |||
| 1939 | return exec_queue_reset(q) || exec_queue_killed_or_banned_or_wedged(q); | 2385 | return exec_queue_reset(q) || exec_queue_killed_or_banned_or_wedged(q); |
| 1940 | } | 2386 | } |
| 1941 | 2387 | ||
| @@ -1953,6 +2399,7 @@ static const struct xe_exec_queue_ops guc_exec_queue_ops = { · 11 unmodified lines | |||
| 1953 | .set_priority = guc_exec_queue_set_priority, | 2399 | .set_priority = guc_exec_queue_set_priority, |
| 1954 | .set_timeslice = guc_exec_queue_set_timeslice, | 2400 | .set_timeslice = guc_exec_queue_set_timeslice, |
| 1955 | .set_preempt_timeout = guc_exec_queue_set_preempt_timeout, | 2401 | .set_preempt_timeout = guc_exec_queue_set_preempt_timeout, |
| 2402 | .set_multi_queue_priority = guc_exec_queue_set_multi_queue_priority, | ||
| 1956 | .suspend = guc_exec_queue_suspend, | 2403 | .suspend = guc_exec_queue_suspend, |
| 1957 | .suspend_wait = guc_exec_queue_suspend_wait, | 2404 | .suspend_wait = guc_exec_queue_suspend_wait, |
| 1958 | .resume = guc_exec_queue_resume, | 2405 | .resume = guc_exec_queue_resume, |
| @@ -2202,6 +2649,22 @@ void xe_guc_submit_pause(struct xe_guc *guc) · 243 unmodified lines | |||
| 2202 | struct xe_exec_queue *q; | 2649 | struct xe_exec_queue *q; |
| 2203 | unsigned long index; | 2650 | unsigned long index; |
| 2204 | 2651 | ||
| 2652 | mutex_lock(&guc->submission_state.lock); | ||
| 2653 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) | ||
| 2654 | xe_sched_submission_stop(&q->guc->sched); | ||
| 2655 | mutex_unlock(&guc->submission_state.lock); | ||
| 2656 | } | ||
| 2657 | |||
| 2658 | /** | ||
| 2659 | * xe_guc_submit_pause_vf - Stop further runs of submission tasks for VF. | ||
| 2660 | * @guc: the &xe_guc struct instance whose scheduler is to be disabled | ||
| 2661 | */ | ||
| 2662 | void xe_guc_submit_pause_vf(struct xe_guc *guc) | ||
| 2663 | { | ||
| 2664 | struct xe_exec_queue *q; | ||
| 2665 | unsigned long index; | ||
| 2666 | |||
| 2667 | xe_gt_assert(guc_to_gt(guc), IS_SRIOV_VF(guc_to_xe(guc))); | ||
| 2205 | xe_gt_assert(guc_to_gt(guc), vf_recovery(guc)); | 2668 | xe_gt_assert(guc_to_gt(guc), vf_recovery(guc)); |
| 2206 | 2669 | ||
| 2207 | mutex_lock(&guc->submission_state.lock); | 2670 | mutex_lock(&guc->submission_state.lock); |
| @@ -2293,14 +2756,15 @@ static void guc_exec_queue_unpause_prepare(struct xe_guc *guc, · 85 unmodified lines | |||
| 2293 | } | 2756 | } |
| 2294 | 2757 | ||
| 2295 | /** | 2758 | /** |
| 2296 | * xe_guc_submit_unpause_prepare - Prepare unpause submission tasks on given GuC. | 2759 | * xe_guc_submit_unpause_prepare_vf - Prepare unpause submission tasks for VF. |
| 2297 | * @guc: the &xe_guc struct instance whose scheduler is to be prepared for unpause | 2760 | * @guc: the &xe_guc struct instance whose scheduler is to be prepared for unpause |
| 2298 | */ | 2761 | */ |
| 2299 | void xe_guc_submit_unpause_prepare(struct xe_guc *guc) | 2762 | void xe_guc_submit_unpause_prepare_vf(struct xe_guc *guc) |
| 2300 | { | 2763 | { |
| 2301 | struct xe_exec_queue *q; | 2764 | struct xe_exec_queue *q; |
| 2302 | unsigned long index; | 2765 | unsigned long index; |
| 2303 | 2766 | ||
| 2767 | xe_gt_assert(guc_to_gt(guc), IS_SRIOV_VF(guc_to_xe(guc))); | ||
| 2304 | xe_gt_assert(guc_to_gt(guc), vf_recovery(guc)); | 2768 | xe_gt_assert(guc_to_gt(guc), vf_recovery(guc)); |
| 2305 | 2769 | ||
| 2306 | mutex_lock(&guc->submission_state.lock); | 2770 | mutex_lock(&guc->submission_state.lock); |
| @@ -2376,6 +2840,23 @@ void xe_guc_submit_unpause(struct xe_guc *guc) · 69 unmodified lines | |||
| 2376 | struct xe_exec_queue *q; | 2840 | struct xe_exec_queue *q; |
| 2377 | unsigned long index; | 2841 | unsigned long index; |
| 2378 | 2842 | ||
| 2843 | mutex_lock(&guc->submission_state.lock); | ||
| 2844 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) | ||
| 2845 | xe_sched_submission_start(&q->guc->sched); | ||
| 2846 | mutex_unlock(&guc->submission_state.lock); | ||
| 2847 | } | ||
| 2848 | |||
| 2849 | /** | ||
| 2850 | * xe_guc_submit_unpause_vf - Allow further runs of submission tasks for VF. | ||
| 2851 | * @guc: the &xe_guc struct instance whose scheduler is to be enabled | ||
| 2852 | */ | ||
| 2853 | void xe_guc_submit_unpause_vf(struct xe_guc *guc) | ||
| 2854 | { | ||
| 2855 | struct xe_exec_queue *q; | ||
| 2856 | unsigned long index; | ||
| 2857 | |||
| 2858 | xe_gt_assert(guc_to_gt(guc), IS_SRIOV_VF(guc_to_xe(guc))); | ||
| 2859 | |||
| 2379 | mutex_lock(&guc->submission_state.lock); | 2860 | mutex_lock(&guc->submission_state.lock); |
| 2380 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) { | 2861 | xa_for_each(&guc->submission_state.exec_queue_lookup, index, q) { |
| 2381 | /* | 2862 | /* |
| @@ -2452,7 +2933,11 @@ static void deregister_exec_queue(struct xe_guc *guc, struct xe_exec_queue *q) · 70 unmodified lines | |||
| 2452 | 2933 | ||
| 2453 | trace_xe_exec_queue_deregister(q); | 2934 | trace_xe_exec_queue_deregister(q); |
| 2454 | 2935 | ||
| 2455 | xe_guc_ct_send_g2h_handler(&guc->ct, action, ARRAY_SIZE(action)); | 2936 | if (xe_exec_queue_is_multi_queue_secondary(q)) |
| 2937 | handle_deregister_done(guc, q); | ||
| 2938 | else | ||
| 2939 | xe_guc_ct_send_g2h_handler(&guc->ct, action, | ||
| 2940 | ARRAY_SIZE(action)); | ||
| 2456 | } | 2941 | } |
| 2457 | 2942 | ||
| 2458 | static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, | 2943 | static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, |
| @@ -2502,6 +2987,16 @@ static void handle_sched_done(struct xe_guc *guc, struct xe_exec_queue *q, · 43 unmodified lines | |||
| 2502 | } | 2987 | } |
| 2503 | } | 2988 | } |
| 2504 | 2989 | ||
| 2990 | static void handle_multi_queue_secondary_sched_done(struct xe_guc *guc, | ||
| 2991 | struct xe_exec_queue *q, | ||
| 2992 | u32 runnable_state) | ||
| 2993 | { | ||
| 2994 | /* Take CT lock here as handle_sched_done() do send a h2g message */ | ||
| 2995 | mutex_lock(&guc->ct.lock); | ||
| 2996 | handle_sched_done(guc, q, runnable_state); | ||
| 2997 | mutex_unlock(&guc->ct.lock); | ||
| 2998 | } | ||
| 2999 | |||
| 2505 | int xe_guc_sched_done_handler(struct xe_guc *guc, u32 *msg, u32 len) | 3000 | int xe_guc_sched_done_handler(struct xe_guc *guc, u32 *msg, u32 len) |
| 2506 | { | 3001 | { |
| 2507 | struct xe_exec_queue *q; | 3002 | struct xe_exec_queue *q; |
| @@ -2585,8 +3080,9 @@ int xe_guc_exec_queue_reset_handler(struct xe_guc *guc, u32 *msg, u32 len) · 77 unmodified lines | |||
| 2585 | if (unlikely(!q)) | 3080 | if (unlikely(!q)) |
| 2586 | return -EPROTO; | 3081 | return -EPROTO; |
| 2587 | 3082 | ||
| 2588 | xe_gt_info(gt, "Engine reset: engine_class=%s, logical_mask: 0x%x, guc_id=%d", | 3083 | xe_gt_info(gt, "Engine reset: engine_class=%s, logical_mask: 0x%x, guc_id=%d, state=0x%0x", |
| 2589 | xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id); | 3084 | xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id, |
| 3085 | atomic_read(&q->guc->state)); | ||
| 2590 | 3086 | ||
| 2591 | trace_xe_exec_queue_reset(q); | 3087 | trace_xe_exec_queue_reset(q); |
| 2592 | 3088 | ||
| @@ -2596,9 +3092,7 @@ int xe_guc_exec_queue_reset_handler(struct xe_guc *guc, u32 *msg, u32 len) · 3 unmodified lines | |||
| 2596 | * jobs by setting timeout of the job to the minimum value kicking | 3092 | * jobs by setting timeout of the job to the minimum value kicking |
| 2597 | * guc_exec_queue_timedout_job. | 3093 | * guc_exec_queue_timedout_job. |
| 2598 | */ | 3094 | */ |
| 2599 | set_exec_queue_reset(q); | 3095 | xe_guc_exec_queue_reset_trigger_cleanup(q); |
| 2600 | if (!exec_queue_banned(q) && !exec_queue_check_timeout(q)) | ||
| 2601 | xe_guc_exec_queue_trigger_cleanup(q); | ||
| 2602 | 3096 | ||
| 2603 | return 0; | 3097 | return 0; |
| 2604 | } | 3098 | } |
| @@ -2666,20 +3160,18 @@ int xe_guc_exec_queue_memory_cat_error_handler(struct xe_guc *guc, u32 *msg, · 61 unmodified lines | |||
| 2666 | * See bspec 54047 and 72187 for details. | 3160 | * See bspec 54047 and 72187 for details. |
| 2667 | */ | 3161 | */ |
| 2668 | if (type != XE_GUC_CAT_ERR_TYPE_INVALID) | 3162 | if (type != XE_GUC_CAT_ERR_TYPE_INVALID) |
| 2669 | xe_gt_dbg(gt, | 3163 | xe_gt_info(gt, |
| 2670 | "Engine memory CAT error [%u]: class=%s, logical_mask: 0x%x, guc_id=%d", | 3164 | "Engine memory CAT error [%u]: class=%s, logical_mask: 0x%x, guc_id=%d", |
| 2671 | type, xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id); | 3165 | type, xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id); |
| 2672 | else | 3166 | else |
| 2673 | xe_gt_dbg(gt, | 3167 | xe_gt_info(gt, |
| 2674 | "Engine memory CAT error: class=%s, logical_mask: 0x%x, guc_id=%d", | 3168 | "Engine memory CAT error: class=%s, logical_mask: 0x%x, guc_id=%d", |
| 2675 | xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id); | 3169 | xe_hw_engine_class_to_str(q->class), q->logical_mask, guc_id); |
| 2676 | 3170 | ||
| 2677 | trace_xe_exec_queue_memory_cat_error(q); | 3171 | trace_xe_exec_queue_memory_cat_error(q); |
| 2678 | 3172 | ||
| 2679 | /* Treat the same as engine reset */ | 3173 | /* Treat the same as engine reset */ |
| 2680 | set_exec_queue_reset(q); | 3174 | xe_guc_exec_queue_reset_trigger_cleanup(q); |
| 2681 | if (!exec_queue_banned(q) && !exec_queue_check_timeout(q)) | ||
| 2682 | xe_guc_exec_queue_trigger_cleanup(q); | ||
| 2683 | 3175 | ||
| 2684 | return 0; | 3176 | return 0; |
| 2685 | } | 3177 | } |
| @@ -2706,6 +3198,73 @@ int xe_guc_exec_queue_reset_failure_handler(struct xe_guc *guc, u32 *msg, u32 le · 20 unmodified lines | |||
| 2706 | return 0; | 3198 | return 0; |
| 2707 | } | 3199 | } |
| 2708 | 3200 | ||
| 3201 | int xe_guc_exec_queue_cgp_context_error_handler(struct xe_guc *guc, u32 *msg, | ||
| 3202 | u32 len) | ||
| 3203 | { | ||
| 3204 | struct xe_gt *gt = guc_to_gt(guc); | ||
| 3205 | struct xe_device *xe = guc_to_xe(guc); | ||
| 3206 | struct xe_exec_queue *q; | ||
| 3207 | u32 guc_id = msg[2]; | ||
| 3208 | |||
| 3209 | if (unlikely(len != XE_GUC_EXEC_QUEUE_CGP_CONTEXT_ERROR_LEN)) { | ||
| 3210 | drm_err(&xe->drm, "Invalid length %u", len); | ||
| 3211 | return -EPROTO; | ||
| 3212 | } | ||
| 3213 | |||
| 3214 | q = g2h_exec_queue_lookup(guc, guc_id); | ||
| 3215 | if (unlikely(!q)) | ||
| 3216 | return -EPROTO; | ||
| 3217 | |||
| 3218 | xe_gt_dbg(gt, | ||
| 3219 | "CGP context error: [%s] err=0x%x, q0_id=0x%x LRCA=0x%x guc_id=0x%x", | ||
| 3220 | msg[0] & 1 ? "uc" : "kmd", msg[1], msg[2], msg[3], msg[4]); | ||
| 3221 | |||
| 3222 | trace_xe_exec_queue_cgp_context_error(q); | ||
| 3223 | |||
| 3224 | /* Treat the same as engine reset */ | ||
| 3225 | xe_guc_exec_queue_reset_trigger_cleanup(q); | ||
| 3226 | |||
| 3227 | return 0; | ||
| 3228 | } | ||
| 3229 | |||
| 3230 | /** | ||
| 3231 | * xe_guc_exec_queue_cgp_sync_done_handler - CGP synchronization done handler | ||
| 3232 | * @guc: guc | ||
| 3233 | * @msg: message indicating CGP sync done | ||
| 3234 | * @len: length of message | ||
| 3235 | * | ||
| 3236 | * Set multi queue group's sync_pending flag to false and wakeup anyone waiting | ||
| 3237 | * for CGP synchronization to complete. | ||
| 3238 | * | ||
| 3239 | * Return: 0 on success, -EPROTO for malformed messages. | ||
| 3240 | */ | ||
| 3241 | int xe_guc_exec_queue_cgp_sync_done_handler(struct xe_guc *guc, u32 *msg, u32 len) | ||
| 3242 | { | ||
| 3243 | struct xe_device *xe = guc_to_xe(guc); | ||
| 3244 | struct xe_exec_queue *q; | ||
| 3245 | u32 guc_id = msg[0]; | ||
| 3246 | |||
| 3247 | if (unlikely(len < 1)) { | ||
| 3248 | drm_err(&xe->drm, "Invalid CGP_SYNC_DONE length %u", len); | ||
| 3249 | return -EPROTO; | ||
| 3250 | } | ||
| 3251 | |||
| 3252 | q = g2h_exec_queue_lookup(guc, guc_id); | ||
| 3253 | if (unlikely(!q)) | ||
| 3254 | return -EPROTO; | ||
| 3255 | |||
| 3256 | if (!xe_exec_queue_is_multi_queue_primary(q)) { | ||
| 3257 | drm_err(&xe->drm, "Unexpected CGP_SYNC_DONE response"); | ||
| 3258 | return -EPROTO; | ||
| 3259 | } | ||
| 3260 | |||
| 3261 | /* Wakeup the serialized cgp update wait */ | ||
| 3262 | WRITE_ONCE(q->multi_queue.group->sync_pending, false); | ||
| 3263 | xe_guc_ct_wake_waiters(&guc->ct); | ||
| 3264 | |||
| 3265 | return 0; | ||
| 3266 | } | ||
| 3267 | |||
| 2709 | static void | 3268 | static void |
| 2710 | guc_exec_queue_wq_snapshot_capture(struct xe_exec_queue *q, | 3269 | guc_exec_queue_wq_snapshot_capture(struct xe_exec_queue *q, |
| 2711 | struct xe_guc_submit_exec_queue_snapshot *snapshot) | 3270 | struct xe_guc_submit_exec_queue_snapshot *snapshot) |
| @@ -2805,6 +3364,11 @@ xe_guc_exec_queue_snapshot_capture(struct xe_exec_queue *q) · 93 unmodified lines | |||
| 2805 | if (snapshot->parallel_execution) | 3364 | if (snapshot->parallel_execution) |
| 2806 | guc_exec_queue_wq_snapshot_capture(q, snapshot); | 3365 | guc_exec_queue_wq_snapshot_capture(q, snapshot); |
| 2807 | 3366 | ||
| 3367 | if (xe_exec_queue_is_multi_queue(q)) { | ||
| 3368 | snapshot->multi_queue.valid = true; | ||
| 3369 | snapshot->multi_queue.primary = xe_exec_queue_multi_queue_primary(q)->guc->id; | ||
| 3370 | snapshot->multi_queue.pos = q->multi_queue.pos; | ||
| 3371 | } | ||
| 2808 | spin_lock(&sched->base.job_list_lock); | 3372 | spin_lock(&sched->base.job_list_lock); |
| 2809 | snapshot->pending_list_size = list_count_nodes(&sched->base.pending_list); | 3373 | snapshot->pending_list_size = list_count_nodes(&sched->base.pending_list); |
| 2810 | snapshot->pending_list = kmalloc_array(snapshot->pending_list_size, | 3374 | snapshot->pending_list = kmalloc_array(snapshot->pending_list_size, |
| @@ -2887,6 +3451,11 @@ xe_guc_exec_queue_snapshot_print(struct xe_guc_submit_exec_queue_snapshot *snaps · 76 unmodified lines | |||
| 2887 | if (snapshot->parallel_execution) | 3451 | if (snapshot->parallel_execution) |
| 2888 | guc_exec_queue_wq_snapshot_print(snapshot, p); | 3452 | guc_exec_queue_wq_snapshot_print(snapshot, p); |
| 2889 | 3453 | ||
| 3454 | if (snapshot->multi_queue.valid) { | ||
| 3455 | drm_printf(p, "\tMulti queue primary GuC ID: %d\n", snapshot->multi_queue.primary); | ||
| 3456 | drm_printf(p, "\tMulti queue position: %d\n", snapshot->multi_queue.pos); | ||
| 3457 | } | ||
| 3458 | |||
| 2890 | for (i = 0; snapshot->pending_list && i < snapshot->pending_list_size; | 3459 | for (i = 0; snapshot->pending_list && i < snapshot->pending_list_size; |
| 2891 | i++) | 3460 | i++) |
| 2892 | drm_printf(p, "\tJob: seqno=%d, fence=%d, finished=%d\n", | 3461 | drm_printf(p, "\tJob: seqno=%d, fence=%d, finished=%d\n", |
| @@ -21,9 +21,11 @@ void xe_guc_submit_reset_wait(struct xe_guc *guc); · 20 unmodified lines | |||
| 21 | void xe_guc_submit_stop(struct xe_guc *guc); | 21 | void xe_guc_submit_stop(struct xe_guc *guc); |
| 22 | int xe_guc_submit_start(struct xe_guc *guc); | 22 | int xe_guc_submit_start(struct xe_guc *guc); |
| 23 | void xe_guc_submit_pause(struct xe_guc *guc); | 23 | void xe_guc_submit_pause(struct xe_guc *guc); |
| 24 | void xe_guc_submit_unpause(struct xe_guc *guc); | ||
| 25 | void xe_guc_submit_unpause_prepare(struct xe_guc *guc); | ||
| 26 | void xe_guc_submit_pause_abort(struct xe_guc *guc); | 24 | void xe_guc_submit_pause_abort(struct xe_guc *guc); |
| 25 | void xe_guc_submit_pause_vf(struct xe_guc *guc); | ||
| 26 | void xe_guc_submit_unpause(struct xe_guc *guc); | ||
| 27 | void xe_guc_submit_unpause_vf(struct xe_guc *guc); | ||
| 28 | void xe_guc_submit_unpause_prepare_vf(struct xe_guc *guc); | ||
| 27 | void xe_guc_submit_wedge(struct xe_guc *guc); | 29 | void xe_guc_submit_wedge(struct xe_guc *guc); |
| 28 | 30 | ||
| 29 | int xe_guc_read_stopped(struct xe_guc *guc); | 31 | int xe_guc_read_stopped(struct xe_guc *guc); |
| @@ -34,6 +36,9 @@ int xe_guc_exec_queue_memory_cat_error_handler(struct xe_guc *guc, u32 *msg, · 4 unmodified lines | |||
| 34 | u32 len); | 36 | u32 len); |
| 35 | int xe_guc_exec_queue_reset_failure_handler(struct xe_guc *guc, u32 *msg, u32 len); | 37 | int xe_guc_exec_queue_reset_failure_handler(struct xe_guc *guc, u32 *msg, u32 len); |
| 36 | int xe_guc_error_capture_handler(struct xe_guc *guc, u32 *msg, u32 len); | 38 | int xe_guc_error_capture_handler(struct xe_guc *guc, u32 *msg, u32 len); |
| 39 | int xe_guc_exec_queue_cgp_sync_done_handler(struct xe_guc *guc, u32 *msg, u32 len); | ||
| 40 | int xe_guc_exec_queue_cgp_context_error_handler(struct xe_guc *guc, u32 *msg, | ||
| 41 | u32 len); | ||
| 37 | 42 | ||
| 38 | struct xe_guc_submit_exec_queue_snapshot * | 43 | struct xe_guc_submit_exec_queue_snapshot * |
| 39 | xe_guc_exec_queue_snapshot_capture(struct xe_exec_queue *q); | 44 | xe_guc_exec_queue_snapshot_capture(struct xe_exec_queue *q); |
| @@ -135,6 +135,19 @@ struct xe_guc_submit_exec_queue_snapshot { · 134 unmodified lines | |||
| 135 | u32 wq[WQ_SIZE / sizeof(u32)]; | 135 | u32 wq[WQ_SIZE / sizeof(u32)]; |
| 136 | } parallel; | 136 | } parallel; |
| 137 | 137 | ||
| 138 | /** @multi_queue: snapshot of the multi queue information */ | ||
| 139 | struct { | ||
| 140 | /** | ||
| 141 | * @multi_queue.primary: GuC id of the primary exec queue | ||
| 142 | * of the multi queue group. | ||
| 143 | */ | ||
| 144 | u32 primary; | ||
| 145 | /** @multi_queue.pos: Position of the exec queue within the multi queue group */ | ||
| 146 | u8 pos; | ||
| 147 | /** @valid: The exec queue is part of a multi queue group */ | ||
| 148 | bool valid; | ||
| 149 | } multi_queue; | ||
| 150 | |||
| 138 | /** @pending_list_size: Size of the pending list snapshot array */ | 151 | /** @pending_list_size: Size of the pending list snapshot array */ |
| 139 | int pending_list_size; | 152 | int pending_list_size; |
| 140 | /** @pending_list: snapshot of the pending list info */ | 153 | /** @pending_list: snapshot of the pending list info */ |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include "xe_guc_tlb_inval.h" | 13 | #include "xe_guc_tlb_inval.h" |
| 14 | #include "xe_force_wake.h" | 14 | #include "xe_force_wake.h" |
| 15 | #include "xe_mmio.h" | 15 | #include "xe_mmio.h" |
| 16 | #include "xe_sa.h" | ||
| 16 | #include "xe_tlb_inval.h" | 17 | #include "xe_tlb_inval.h" |
| 17 | 18 | ||
| 18 | #include "regs/xe_guc_regs.h" | 19 | #include "regs/xe_guc_regs.h" |
| @@ -34,9 +35,12 @@ static int send_tlb_inval(struct xe_guc *guc, const u32 *action, int len) · 15 unmodified lines | |||
| 34 | G2H_LEN_DW_TLB_INVALIDATE, 1); | 35 | G2H_LEN_DW_TLB_INVALIDATE, 1); |
| 35 | } | 36 | } |
| 36 | 37 | ||
| 37 | #define MAKE_INVAL_OP(type) ((type << XE_GUC_TLB_INVAL_TYPE_SHIFT) | \ | 38 | #define MAKE_INVAL_OP_FLUSH(type, flush_cache) ((type << XE_GUC_TLB_INVAL_TYPE_SHIFT) | \ |
| 38 | XE_GUC_TLB_INVAL_MODE_HEAVY << XE_GUC_TLB_INVAL_MODE_SHIFT | \ | 39 | XE_GUC_TLB_INVAL_MODE_HEAVY << XE_GUC_TLB_INVAL_MODE_SHIFT | \ |
| 39 | XE_GUC_TLB_INVAL_FLUSH_CACHE) | 40 | (flush_cache ? \ |
| 41 | XE_GUC_TLB_INVAL_FLUSH_CACHE : 0)) | ||
| 42 | |||
| 43 | #define MAKE_INVAL_OP(type) MAKE_INVAL_OP_FLUSH(type, true) | ||
| 40 | 44 | ||
| 41 | static int send_tlb_inval_all(struct xe_tlb_inval *tlb_inval, u32 seqno) | 45 | static int send_tlb_inval_all(struct xe_tlb_inval *tlb_inval, u32 seqno) |
| 42 | { | 46 | { |
| @@ -71,12 +75,11 @@ static int send_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval, u32 seqno) · 28 unmodified lines | |||
| 71 | return send_tlb_inval(guc, action, ARRAY_SIZE(action)); | 75 | return send_tlb_inval(guc, action, ARRAY_SIZE(action)); |
| 72 | } else if (xe_device_uc_enabled(xe) && !xe_device_wedged(xe)) { | 76 | } else if (xe_device_uc_enabled(xe) && !xe_device_wedged(xe)) { |
| 73 | struct xe_mmio *mmio = >->mmio; | 77 | struct xe_mmio *mmio = >->mmio; |
| 74 | unsigned int fw_ref; | ||
| 75 | 78 | ||
| 76 | if (IS_SRIOV_VF(xe)) | 79 | if (IS_SRIOV_VF(xe)) |
| 77 | return -ECANCELED; | 80 | return -ECANCELED; |
| 78 | 81 | ||
| 79 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 82 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 80 | if (xe->info.platform == XE_PVC || GRAPHICS_VER(xe) >= 20) { | 83 | if (xe->info.platform == XE_PVC || GRAPHICS_VER(xe) >= 20) { |
| 81 | xe_mmio_write32(mmio, PVC_GUC_TLB_INV_DESC1, | 84 | xe_mmio_write32(mmio, PVC_GUC_TLB_INV_DESC1, |
| 82 | PVC_GUC_TLB_INV_DESC1_INVALIDATE); | 85 | PVC_GUC_TLB_INV_DESC1_INVALIDATE); |
| @@ -86,12 +89,25 @@ static int send_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval, u32 seqno) · 3 unmodified lines | |||
| 86 | xe_mmio_write32(mmio, GUC_TLB_INV_CR, | 89 | xe_mmio_write32(mmio, GUC_TLB_INV_CR, |
| 87 | GUC_TLB_INV_CR_INVALIDATE); | 90 | GUC_TLB_INV_CR_INVALIDATE); |
| 88 | } | 91 | } |
| 89 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 90 | } | 92 | } |
| 91 | 93 | ||
| 92 | return -ECANCELED; | 94 | return -ECANCELED; |
| 93 | } | 95 | } |
| 94 | 96 | ||
| 97 | static int send_page_reclaim(struct xe_guc *guc, u32 seqno, | ||
| 98 | u64 gpu_addr) | ||
| 99 | { | ||
| 100 | u32 action[] = { | ||
| 101 | XE_GUC_ACTION_PAGE_RECLAMATION, | ||
| 102 | seqno, | ||
| 103 | lower_32_bits(gpu_addr), | ||
| 104 | upper_32_bits(gpu_addr), | ||
| 105 | }; | ||
| 106 | |||
| 107 | return xe_guc_ct_send(&guc->ct, action, ARRAY_SIZE(action), | ||
| 108 | G2H_LEN_DW_PAGE_RECLAMATION, 1); | ||
| 109 | } | ||
| 110 | |||
| 95 | /* | 111 | /* |
| 96 | * Ensure that roundup_pow_of_two(length) doesn't overflow. | 112 | * Ensure that roundup_pow_of_two(length) doesn't overflow. |
| 97 | * Note that roundup_pow_of_two() operates on unsigned long, | 113 | * Note that roundup_pow_of_two() operates on unsigned long, |
| @@ -100,20 +116,21 @@ static int send_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval, u32 seqno) · 2 unmodified lines | |||
| 100 | #define MAX_RANGE_TLB_INVALIDATION_LENGTH (rounddown_pow_of_two(ULONG_MAX)) | 116 | #define MAX_RANGE_TLB_INVALIDATION_LENGTH (rounddown_pow_of_two(ULONG_MAX)) |
| 101 | 117 | ||
| 102 | static int send_tlb_inval_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, | 118 | static int send_tlb_inval_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, |
| 103 | u64 start, u64 end, u32 asid) | 119 | u64 start, u64 end, u32 asid, |
| 120 | struct drm_suballoc *prl_sa) | ||
| 104 | { | 121 | { |
| 105 | #define MAX_TLB_INVALIDATION_LEN 7 | 122 | #define MAX_TLB_INVALIDATION_LEN 7 |
| 106 | struct xe_guc *guc = tlb_inval->private; | 123 | struct xe_guc *guc = tlb_inval->private; |
| 107 | struct xe_gt *gt = guc_to_gt(guc); | 124 | struct xe_gt *gt = guc_to_gt(guc); |
| 108 | u32 action[MAX_TLB_INVALIDATION_LEN]; | 125 | u32 action[MAX_TLB_INVALIDATION_LEN]; |
| 109 | u64 length = end - start; | 126 | u64 length = end - start; |
| 110 | int len = 0; | 127 | int len = 0, err; |
| 111 | 128 | ||
| 112 | if (guc_to_xe(guc)->info.force_execlist) | 129 | if (guc_to_xe(guc)->info.force_execlist) |
| 113 | return -ECANCELED; | 130 | return -ECANCELED; |
| 114 | 131 | ||
| 115 | action[len++] = XE_GUC_ACTION_TLB_INVALIDATION; | 132 | action[len++] = XE_GUC_ACTION_TLB_INVALIDATION; |
| 116 | action[len++] = seqno; | 133 | action[len++] = !prl_sa ? seqno : TLB_INVALIDATION_SEQNO_INVALID; |
| 117 | if (!gt_to_xe(gt)->info.has_range_tlb_inval || | 134 | if (!gt_to_xe(gt)->info.has_range_tlb_inval || |
| 118 | length > MAX_RANGE_TLB_INVALIDATION_LENGTH) { | 135 | length > MAX_RANGE_TLB_INVALIDATION_LENGTH) { |
| 119 | action[len++] = MAKE_INVAL_OP(XE_GUC_TLB_INVAL_FULL); | 136 | action[len++] = MAKE_INVAL_OP(XE_GUC_TLB_INVAL_FULL); |
| @@ -154,7 +171,8 @@ static int send_tlb_inval_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, · 34 unmodified lines | |||
| 154 | ilog2(SZ_2M) + 1))); | 171 | ilog2(SZ_2M) + 1))); |
| 155 | xe_gt_assert(gt, IS_ALIGNED(start, length)); | 172 | xe_gt_assert(gt, IS_ALIGNED(start, length)); |
| 156 | 173 | ||
| 157 | action[len++] = MAKE_INVAL_OP(XE_GUC_TLB_INVAL_PAGE_SELECTIVE); | 174 | /* Flush on NULL case, Media is not required to modify flush due to no PPC so NOP */ |
| 175 | action[len++] = MAKE_INVAL_OP_FLUSH(XE_GUC_TLB_INVAL_PAGE_SELECTIVE, !prl_sa); | ||
| 158 | action[len++] = asid; | 176 | action[len++] = asid; |
| 159 | action[len++] = lower_32_bits(start); | 177 | action[len++] = lower_32_bits(start); |
| 160 | action[len++] = upper_32_bits(start); | 178 | action[len++] = upper_32_bits(start); |
| @@ -163,7 +181,10 @@ static int send_tlb_inval_ppgtt(struct xe_tlb_inval *tlb_inval, u32 seqno, · 2 unmodified lines | |||
| 163 | 181 | ||
| 164 | xe_gt_assert(gt, len <= MAX_TLB_INVALIDATION_LEN); | 182 | xe_gt_assert(gt, len <= MAX_TLB_INVALIDATION_LEN); |
| 165 | 183 | ||
| 166 | return send_tlb_inval(guc, action, len); | 184 | err = send_tlb_inval(guc, action, len); |
| 185 | if (!err && prl_sa) | ||
| 186 | err = send_page_reclaim(guc, seqno, xe_sa_bo_gpu_addr(prl_sa)); | ||
| 187 | return err; | ||
| 167 | } | 188 | } |
| 168 | 189 | ||
| 169 | static bool tlb_inval_initialized(struct xe_tlb_inval *tlb_inval) | 190 | static bool tlb_inval_initialized(struct xe_tlb_inval *tlb_inval) |
| @@ -300,19 +300,16 @@ void xe_huc_sanitize(struct xe_huc *huc) · 299 unmodified lines | |||
| 300 | void xe_huc_print_info(struct xe_huc *huc, struct drm_printer *p) | 300 | void xe_huc_print_info(struct xe_huc *huc, struct drm_printer *p) |
| 301 | { | 301 | { |
| 302 | struct xe_gt *gt = huc_to_gt(huc); | 302 | struct xe_gt *gt = huc_to_gt(huc); |
| 303 | unsigned int fw_ref; | ||
| 304 | 303 | ||
| 305 | xe_uc_fw_print(&huc->fw, p); | 304 | xe_uc_fw_print(&huc->fw, p); |
| 306 | 305 | ||
| 307 | if (!xe_uc_fw_is_enabled(&huc->fw)) | 306 | if (!xe_uc_fw_is_enabled(&huc->fw)) |
| 308 | return; | 307 | return; |
| 309 | 308 | ||
| 310 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 309 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 311 | if (!fw_ref) | 310 | if (!fw_ref.domains) |
| 312 | return; | 311 | return; |
| 313 | 312 | ||
| 314 | drm_printf(p, "\nHuC status: 0x%08x\n", | 313 | drm_printf(p, "\nHuC status: 0x%08x\n", |
| 315 | xe_mmio_read32(>->mmio, HUC_KERNEL_LOAD_INFO)); | 314 | xe_mmio_read32(>->mmio, HUC_KERNEL_LOAD_INFO)); |
| 316 | |||
| 317 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 318 | } | 315 | } |
| @@ -37,9 +37,8 @@ static int huc_info(struct seq_file *m, void *data) · 36 unmodified lines | |||
| 37 | struct xe_device *xe = huc_to_xe(huc); | 37 | struct xe_device *xe = huc_to_xe(huc); |
| 38 | struct drm_printer p = drm_seq_file_printer(m); | 38 | struct drm_printer p = drm_seq_file_printer(m); |
| 39 | 39 | ||
| 40 | xe_pm_runtime_get(xe); | 40 | guard(xe_pm_runtime)(xe); |
| 41 | xe_huc_print_info(huc, &p); | 41 | xe_huc_print_info(huc, &p); |
| 42 | xe_pm_runtime_put(xe); | ||
| 43 | 42 | ||
| 44 | return 0; | 43 | return 0; |
| 45 | } | 44 | } |
| @@ -43,16 +43,14 @@ static ssize_t xe_hw_engine_class_sysfs_attr_show(struct kobject *kobj, · 42 unmodified lines | |||
| 43 | { | 43 | { |
| 44 | struct xe_device *xe = kobj_to_xe(kobj); | 44 | struct xe_device *xe = kobj_to_xe(kobj); |
| 45 | struct kobj_attribute *kattr; | 45 | struct kobj_attribute *kattr; |
| 46 | ssize_t ret = -EIO; | ||
| 47 | 46 | ||
| 48 | kattr = container_of(attr, struct kobj_attribute, attr); | 47 | kattr = container_of(attr, struct kobj_attribute, attr); |
| 49 | if (kattr->show) { | 48 | if (kattr->show) { |
| 50 | xe_pm_runtime_get(xe); | 49 | guard(xe_pm_runtime)(xe); |
| 51 | ret = kattr->show(kobj, kattr, buf); | 50 | return kattr->show(kobj, kattr, buf); |
| 52 | xe_pm_runtime_put(xe); | ||
| 53 | } | 51 | } |
| 54 | 52 | ||
| 55 | return ret; | 53 | return -EIO; |
| 56 | } | 54 | } |
| 57 | 55 | ||
| 58 | static ssize_t xe_hw_engine_class_sysfs_attr_store(struct kobject *kobj, | 56 | static ssize_t xe_hw_engine_class_sysfs_attr_store(struct kobject *kobj, |
| @@ -62,16 +60,14 @@ static ssize_t xe_hw_engine_class_sysfs_attr_store(struct kobject *kobj, · 3 unmodified lines | |||
| 62 | { | 60 | { |
| 63 | struct xe_device *xe = kobj_to_xe(kobj); | 61 | struct xe_device *xe = kobj_to_xe(kobj); |
| 64 | struct kobj_attribute *kattr; | 62 | struct kobj_attribute *kattr; |
| 65 | ssize_t ret = -EIO; | ||
| 66 | 63 | ||
| 67 | kattr = container_of(attr, struct kobj_attribute, attr); | 64 | kattr = container_of(attr, struct kobj_attribute, attr); |
| 68 | if (kattr->store) { | 65 | if (kattr->store) { |
| 69 | xe_pm_runtime_get(xe); | 66 | guard(xe_pm_runtime)(xe); |
| 70 | ret = kattr->store(kobj, kattr, buf, count); | 67 | return kattr->store(kobj, kattr, buf, count); |
| 71 | xe_pm_runtime_put(xe); | ||
| 72 | } | 68 | } |
| 73 | 69 | ||
| 74 | return ret; | 70 | return -EIO; |
| 75 | } | 71 | } |
| 76 | 72 | ||
| 77 | static const struct sysfs_ops xe_hw_engine_class_sysfs_ops = { | 73 | static const struct sysfs_ops xe_hw_engine_class_sysfs_ops = { |
| @@ -9,7 +9,9 @@ · 8 unmodified lines | |||
| 9 | #include "xe_device.h" | 9 | #include "xe_device.h" |
| 10 | #include "xe_exec_queue.h" | 10 | #include "xe_exec_queue.h" |
| 11 | #include "xe_gt.h" | 11 | #include "xe_gt.h" |
| 12 | #include "xe_gt_stats.h" | ||
| 12 | #include "xe_hw_engine_group.h" | 13 | #include "xe_hw_engine_group.h" |
| 14 | #include "xe_sync.h" | ||
| 13 | #include "xe_vm.h" | 15 | #include "xe_vm.h" |
| 14 | 16 | ||
| 15 | static void | 17 | static void |
| @@ -20,7 +22,8 @@ hw_engine_group_resume_lr_jobs_func(struct work_struct *w) · 4 unmodified lines | |||
| 20 | int err; | 22 | int err; |
| 21 | enum xe_hw_engine_group_execution_mode previous_mode; | 23 | enum xe_hw_engine_group_execution_mode previous_mode; |
| 22 | 24 | ||
| 23 | err = xe_hw_engine_group_get_mode(group, EXEC_MODE_LR, &previous_mode); | 25 | err = xe_hw_engine_group_get_mode(group, EXEC_MODE_LR, &previous_mode, |
| 26 | NULL, 0); | ||
| 24 | if (err) | 27 | if (err) |
| 25 | return; | 28 | return; |
| 26 | 29 | ||
| @@ -188,23 +191,39 @@ void xe_hw_engine_group_resume_faulting_lr_jobs(struct xe_hw_engine_group *group · 161 unmodified lines | |||
| 188 | /** | 191 | /** |
| 189 | * xe_hw_engine_group_suspend_faulting_lr_jobs() - Suspend the faulting LR jobs of this group | 192 | * xe_hw_engine_group_suspend_faulting_lr_jobs() - Suspend the faulting LR jobs of this group |
| 190 | * @group: The hw engine group | 193 | * @group: The hw engine group |
| 194 | * @has_deps: dma-fence job triggering suspend has dependencies | ||
| 191 | * | 195 | * |
| 192 | * Return: 0 on success, negative error code on error. | 196 | * Return: 0 on success, negative error code on error. |
| 193 | */ | 197 | */ |
| 194 | static int xe_hw_engine_group_suspend_faulting_lr_jobs(struct xe_hw_engine_group *group) | 198 | static int xe_hw_engine_group_suspend_faulting_lr_jobs(struct xe_hw_engine_group *group, |
| 199 | bool has_deps) | ||
| 195 | { | 200 | { |
| 196 | int err; | 201 | int err; |
| 197 | struct xe_exec_queue *q; | 202 | struct xe_exec_queue *q; |
| 203 | struct xe_gt *gt = NULL; | ||
| 198 | bool need_resume = false; | 204 | bool need_resume = false; |
| 205 | ktime_t start = xe_gt_stats_ktime_get(); | ||
| 199 | 206 | ||
| 200 | lockdep_assert_held_write(&group->mode_sem); | 207 | lockdep_assert_held_write(&group->mode_sem); |
| 201 | 208 | ||
| 202 | list_for_each_entry(q, &group->exec_queue_list, hw_engine_group_link) { | 209 | list_for_each_entry(q, &group->exec_queue_list, hw_engine_group_link) { |
| 210 | bool idle_skip_suspend; | ||
| 211 | |||
| 203 | if (!xe_vm_in_fault_mode(q->vm)) | 212 | if (!xe_vm_in_fault_mode(q->vm)) |
| 204 | continue; | 213 | continue; |
| 205 | 214 | ||
| 206 | need_resume = true; | 215 | idle_skip_suspend = xe_exec_queue_idle_skip_suspend(q); |
| 216 | if (!idle_skip_suspend && has_deps) | ||
| 217 | return -EAGAIN; | ||
| 218 | |||
| 219 | xe_gt_stats_incr(q->gt, XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_COUNT, 1); | ||
| 220 | if (idle_skip_suspend) | ||
| 221 | xe_gt_stats_incr(q->gt, | ||
| 222 | XE_GT_STATS_ID_HW_ENGINE_GROUP_SKIP_LR_QUEUE_COUNT, 1); | ||
| 223 | |||
| 224 | need_resume |= !idle_skip_suspend; | ||
| 207 | q->ops->suspend(q); | 225 | q->ops->suspend(q); |
| 226 | gt = q->gt; | ||
| 208 | } | 227 | } |
| 209 | 228 | ||
| 210 | list_for_each_entry(q, &group->exec_queue_list, hw_engine_group_link) { | 229 | list_for_each_entry(q, &group->exec_queue_list, hw_engine_group_link) { |
| @@ -216,6 +235,12 @@ static int xe_hw_engine_group_suspend_faulting_lr_jobs(struct xe_hw_engine_group · 5 unmodified lines | |||
| 216 | return err; | 235 | return err; |
| 217 | } | 236 | } |
| 218 | 237 | ||
| 238 | if (gt) { | ||
| 239 | xe_gt_stats_incr(gt, | ||
| 240 | XE_GT_STATS_ID_HW_ENGINE_GROUP_SUSPEND_LR_QUEUE_US, | ||
| 241 | xe_gt_stats_ktime_us_delta(start)); | ||
| 242 | } | ||
| 243 | |||
| 219 | if (need_resume) | 244 | if (need_resume) |
| 220 | xe_hw_engine_group_resume_faulting_lr_jobs(group); | 245 | xe_hw_engine_group_resume_faulting_lr_jobs(group); |
| 221 | 246 | ||
| @@ -236,7 +261,9 @@ static int xe_hw_engine_group_wait_for_dma_fence_jobs(struct xe_hw_engine_group · 14 unmodified lines | |||
| 236 | { | 261 | { |
| 237 | long timeout; | 262 | long timeout; |
| 238 | struct xe_exec_queue *q; | 263 | struct xe_exec_queue *q; |
| 264 | struct xe_gt *gt = NULL; | ||
| 239 | struct dma_fence *fence; | 265 | struct dma_fence *fence; |
| 266 | ktime_t start = xe_gt_stats_ktime_get(); | ||
| 240 | 267 | ||
| 241 | lockdep_assert_held_write(&group->mode_sem); | 268 | lockdep_assert_held_write(&group->mode_sem); |
| 242 | 269 | ||
| @@ -244,18 +271,26 @@ static int xe_hw_engine_group_wait_for_dma_fence_jobs(struct xe_hw_engine_group · 1 unmodified line | |||
| 244 | if (xe_vm_in_lr_mode(q->vm)) | 271 | if (xe_vm_in_lr_mode(q->vm)) |
| 245 | continue; | 272 | continue; |
| 246 | 273 | ||
| 274 | xe_gt_stats_incr(q->gt, XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_COUNT, 1); | ||
| 247 | fence = xe_exec_queue_last_fence_get_for_resume(q, q->vm); | 275 | fence = xe_exec_queue_last_fence_get_for_resume(q, q->vm); |
| 248 | timeout = dma_fence_wait(fence, false); | 276 | timeout = dma_fence_wait(fence, false); |
| 249 | dma_fence_put(fence); | 277 | dma_fence_put(fence); |
| 278 | gt = q->gt; | ||
| 250 | 279 | ||
| 251 | if (timeout < 0) | 280 | if (timeout < 0) |
| 252 | return -ETIME; | 281 | return -ETIME; |
| 253 | } | 282 | } |
| 254 | 283 | ||
| 284 | if (gt) { | ||
| 285 | xe_gt_stats_incr(gt, | ||
| 286 | XE_GT_STATS_ID_HW_ENGINE_GROUP_WAIT_DMA_QUEUE_US, | ||
| 287 | xe_gt_stats_ktime_us_delta(start)); | ||
| 288 | } | ||
| 289 | |||
| 255 | return 0; | 290 | return 0; |
| 256 | } | 291 | } |
| 257 | 292 | ||
| 258 | static int switch_mode(struct xe_hw_engine_group *group) | 293 | static int switch_mode(struct xe_hw_engine_group *group, bool has_deps) |
| 259 | { | 294 | { |
| 260 | int err = 0; | 295 | int err = 0; |
| 261 | enum xe_hw_engine_group_execution_mode new_mode; | 296 | enum xe_hw_engine_group_execution_mode new_mode; |
| @@ -265,7 +300,8 @@ static int switch_mode(struct xe_hw_engine_group *group) · 3 unmodified lines | |||
| 265 | switch (group->cur_mode) { | 300 | switch (group->cur_mode) { |
| 266 | case EXEC_MODE_LR: | 301 | case EXEC_MODE_LR: |
| 267 | new_mode = EXEC_MODE_DMA_FENCE; | 302 | new_mode = EXEC_MODE_DMA_FENCE; |
| 268 | err = xe_hw_engine_group_suspend_faulting_lr_jobs(group); | 303 | err = xe_hw_engine_group_suspend_faulting_lr_jobs(group, |
| 304 | has_deps); | ||
| 269 | break; | 305 | break; |
| 270 | case EXEC_MODE_DMA_FENCE: | 306 | case EXEC_MODE_DMA_FENCE: |
| 271 | new_mode = EXEC_MODE_LR; | 307 | new_mode = EXEC_MODE_LR; |
| @@ -281,19 +317,36 @@ static int switch_mode(struct xe_hw_engine_group *group) · 9 unmodified lines | |||
| 281 | return 0; | 317 | return 0; |
| 282 | } | 318 | } |
| 283 | 319 | ||
| 320 | static int wait_syncs(struct xe_sync_entry *syncs, int num_syncs) | ||
| 321 | { | ||
| 322 | int err, i; | ||
| 323 | |||
| 324 | for (i = 0; i < num_syncs; ++i) { | ||
| 325 | err = xe_sync_entry_wait(syncs + i); | ||
| 326 | if (err) | ||
| 327 | return err; | ||
| 328 | } | ||
| 329 | |||
| 330 | return 0; | ||
| 331 | } | ||
| 332 | |||
| 284 | /** | 333 | /** |
| 285 | * xe_hw_engine_group_get_mode() - Get the group to execute in the new mode | 334 | * xe_hw_engine_group_get_mode() - Get the group to execute in the new mode |
| 286 | * @group: The hw engine group | 335 | * @group: The hw engine group |
| 287 | * @new_mode: The new execution mode | 336 | * @new_mode: The new execution mode |
| 288 | * @previous_mode: Pointer to the previous mode provided for use by caller | 337 | * @previous_mode: Pointer to the previous mode provided for use by caller |
| 338 | * @syncs: Syncs from exec IOCTL | ||
| 339 | * @num_syncs: Number of syncs from exec IOCTL | ||
| 289 | * | 340 | * |
| 290 | * Return: 0 if successful, -EINTR if locking failed. | 341 | * Return: 0 if successful, -EINTR if locking failed. |
| 291 | */ | 342 | */ |
| 292 | int xe_hw_engine_group_get_mode(struct xe_hw_engine_group *group, | 343 | int xe_hw_engine_group_get_mode(struct xe_hw_engine_group *group, |
| 293 | enum xe_hw_engine_group_execution_mode new_mode, | 344 | enum xe_hw_engine_group_execution_mode new_mode, |
| 294 | enum xe_hw_engine_group_execution_mode *previous_mode) | 345 | enum xe_hw_engine_group_execution_mode *previous_mode, |
| 346 | struct xe_sync_entry *syncs, int num_syncs) | ||
| 295 | __acquires(&group->mode_sem) | 347 | __acquires(&group->mode_sem) |
| 296 | { | 348 | { |
| 349 | bool has_deps = !!num_syncs; | ||
| 297 | int err = down_read_interruptible(&group->mode_sem); | 350 | int err = down_read_interruptible(&group->mode_sem); |
| 298 | 351 | ||
| 299 | if (err) | 352 | if (err) |
| @@ -303,15 +356,25 @@ __acquires(&group->mode_sem) · 3 unmodified lines | |||
| 303 | 356 | ||
| 304 | if (new_mode != group->cur_mode) { | 357 | if (new_mode != group->cur_mode) { |
| 305 | up_read(&group->mode_sem); | 358 | up_read(&group->mode_sem); |
| 359 | retry: | ||
| 306 | err = down_write_killable(&group->mode_sem); | 360 | err = down_write_killable(&group->mode_sem); |
| 307 | if (err) | 361 | if (err) |
| 308 | return err; | 362 | return err; |
| 309 | 363 | ||
| 310 | if (new_mode != group->cur_mode) { | 364 | if (new_mode != group->cur_mode) { |
| 311 | err = switch_mode(group); | 365 | err = switch_mode(group, has_deps); |
| 312 | if (err) { | 366 | if (err) { |
| 313 | up_write(&group->mode_sem); | 367 | up_write(&group->mode_sem); |
| 314 | return err; | 368 | |
| 369 | if (err != -EAGAIN) | ||
| 370 | return err; | ||
| 371 | |||
| 372 | err = wait_syncs(syncs, num_syncs); | ||
| 373 | if (err) | ||
| 374 | return err; | ||
| 375 | |||
| 376 | has_deps = false; | ||
| 377 | goto retry; | ||
| 315 | } | 378 | } |
| 316 | } | 379 | } |
| 317 | downgrade_write(&group->mode_sem); | 380 | downgrade_write(&group->mode_sem); |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | struct drm_device; | 11 | struct drm_device; |
| 12 | struct xe_exec_queue; | 12 | struct xe_exec_queue; |
| 13 | struct xe_gt; | 13 | struct xe_gt; |
| 14 | struct xe_sync_entry; | ||
| 14 | 15 | ||
| 15 | int xe_hw_engine_setup_groups(struct xe_gt *gt); | 16 | int xe_hw_engine_setup_groups(struct xe_gt *gt); |
| 16 | 17 | ||
| @@ -19,7 +20,8 @@ void xe_hw_engine_group_del_exec_queue(struct xe_hw_engine_group *group, struct · 2 unmodified lines | |||
| 19 | 20 | ||
| 20 | int xe_hw_engine_group_get_mode(struct xe_hw_engine_group *group, | 21 | int xe_hw_engine_group_get_mode(struct xe_hw_engine_group *group, |
| 21 | enum xe_hw_engine_group_execution_mode new_mode, | 22 | enum xe_hw_engine_group_execution_mode new_mode, |
| 22 | enum xe_hw_engine_group_execution_mode *previous_mode); | 23 | enum xe_hw_engine_group_execution_mode *previous_mode, |
| 24 | struct xe_sync_entry *syncs, int num_syncs); | ||
| 23 | void xe_hw_engine_group_put(struct xe_hw_engine_group *group); | 25 | void xe_hw_engine_group_put(struct xe_hw_engine_group *group); |
| 24 | 26 | ||
| 25 | enum xe_hw_engine_group_execution_mode | 27 | enum xe_hw_engine_group_execution_mode |
| @@ -502,7 +502,7 @@ xe_hwmon_power_max_interval_show(struct device *dev, struct device_attribute *at · 501 unmodified lines | |||
| 502 | 502 | ||
| 503 | int ret = 0; | 503 | int ret = 0; |
| 504 | 504 | ||
| 505 | xe_pm_runtime_get(hwmon->xe); | 505 | guard(xe_pm_runtime)(hwmon->xe); |
| 506 | 506 | ||
| 507 | mutex_lock(&hwmon->hwmon_lock); | 507 | mutex_lock(&hwmon->hwmon_lock); |
| 508 | 508 | ||
| @@ -521,8 +521,6 @@ xe_hwmon_power_max_interval_show(struct device *dev, struct device_attribute *at · 12 unmodified lines | |||
| 521 | 521 | ||
| 522 | mutex_unlock(&hwmon->hwmon_lock); | 522 | mutex_unlock(&hwmon->hwmon_lock); |
| 523 | 523 | ||
| 524 | xe_pm_runtime_put(hwmon->xe); | ||
| 525 | |||
| 526 | x = REG_FIELD_GET(PWR_LIM_TIME_X, reg_val); | 524 | x = REG_FIELD_GET(PWR_LIM_TIME_X, reg_val); |
| 527 | y = REG_FIELD_GET(PWR_LIM_TIME_Y, reg_val); | 525 | y = REG_FIELD_GET(PWR_LIM_TIME_Y, reg_val); |
| 528 | 526 | ||
| @@ -604,7 +602,7 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a · 75 unmodified lines | |||
| 604 | rxy = REG_FIELD_PREP(PWR_LIM_TIME_X, x) | | 602 | rxy = REG_FIELD_PREP(PWR_LIM_TIME_X, x) | |
| 605 | REG_FIELD_PREP(PWR_LIM_TIME_Y, y); | 603 | REG_FIELD_PREP(PWR_LIM_TIME_Y, y); |
| 606 | 604 | ||
| 607 | xe_pm_runtime_get(hwmon->xe); | 605 | guard(xe_pm_runtime)(hwmon->xe); |
| 608 | 606 | ||
| 609 | mutex_lock(&hwmon->hwmon_lock); | 607 | mutex_lock(&hwmon->hwmon_lock); |
| 610 | 608 | ||
| @@ -616,8 +614,6 @@ xe_hwmon_power_max_interval_store(struct device *dev, struct device_attribute *a · 5 unmodified lines | |||
| 616 | 614 | ||
| 617 | mutex_unlock(&hwmon->hwmon_lock); | 615 | mutex_unlock(&hwmon->hwmon_lock); |
| 618 | 616 | ||
| 619 | xe_pm_runtime_put(hwmon->xe); | ||
| 620 | |||
| 621 | return count; | 617 | return count; |
| 622 | } | 618 | } |
| 623 | 619 | ||
| @@ -1124,37 +1120,25 @@ xe_hwmon_read(struct device *dev, enum hwmon_sensor_types type, u32 attr, · 500 unmodified lines | |||
| 1124 | int channel, long *val) | 1120 | int channel, long *val) |
| 1125 | { | 1121 | { |
| 1126 | struct xe_hwmon *hwmon = dev_get_drvdata(dev); | 1122 | struct xe_hwmon *hwmon = dev_get_drvdata(dev); |
| 1127 | int ret; | ||
| 1128 | 1123 | ||
| 1129 | xe_pm_runtime_get(hwmon->xe); | 1124 | guard(xe_pm_runtime)(hwmon->xe); |
| 1130 | 1125 | ||
| 1131 | switch (type) { | 1126 | switch (type) { |
| 1132 | case hwmon_temp: | 1127 | case hwmon_temp: |
| 1133 | ret = xe_hwmon_temp_read(hwmon, attr, channel, val); | 1128 | return xe_hwmon_temp_read(hwmon, attr, channel, val); |
| 1134 | break; | ||
| 1135 | case hwmon_power: | 1129 | case hwmon_power: |
| 1136 | ret = xe_hwmon_power_read(hwmon, attr, channel, val); | 1130 | return xe_hwmon_power_read(hwmon, attr, channel, val); |
| 1137 | break; | ||
| 1138 | case hwmon_curr: | 1131 | case hwmon_curr: |
| 1139 | ret = xe_hwmon_curr_read(hwmon, attr, channel, val); | 1132 | return xe_hwmon_curr_read(hwmon, attr, channel, val); |
| 1140 | break; | ||
| 1141 | case hwmon_in: | 1133 | case hwmon_in: |
| 1142 | ret = xe_hwmon_in_read(hwmon, attr, channel, val); | 1134 | return xe_hwmon_in_read(hwmon, attr, channel, val); |
| 1143 | break; | ||
| 1144 | case hwmon_energy: | 1135 | case hwmon_energy: |
| 1145 | ret = xe_hwmon_energy_read(hwmon, attr, channel, val); | 1136 | return xe_hwmon_energy_read(hwmon, attr, channel, val); |
| 1146 | break; | ||
| 1147 | case hwmon_fan: | 1137 | case hwmon_fan: |
| 1148 | ret = xe_hwmon_fan_read(hwmon, attr, channel, val); | 1138 | return xe_hwmon_fan_read(hwmon, attr, channel, val); |
| 1149 | break; | ||
| 1150 | default: | 1139 | default: |
| 1151 | ret = -EOPNOTSUPP; | 1140 | return -EOPNOTSUPP; |
| 1152 | break; | ||
| 1153 | } | 1141 | } |
| 1154 | |||
| 1155 | xe_pm_runtime_put(hwmon->xe); | ||
| 1156 | |||
| 1157 | return ret; | ||
| 1158 | } | 1142 | } |
| 1159 | 1143 | ||
| 1160 | static int | 1144 | static int |
| @@ -1162,25 +1146,17 @@ xe_hwmon_write(struct device *dev, enum hwmon_sensor_types type, u32 attr, · 1 unmodified line | |||
| 1162 | int channel, long val) | 1146 | int channel, long val) |
| 1163 | { | 1147 | { |
| 1164 | struct xe_hwmon *hwmon = dev_get_drvdata(dev); | 1148 | struct xe_hwmon *hwmon = dev_get_drvdata(dev); |
| 1165 | int ret; | ||
| 1166 | 1149 | ||
| 1167 | xe_pm_runtime_get(hwmon->xe); | 1150 | guard(xe_pm_runtime)(hwmon->xe); |
| 1168 | 1151 | ||
| 1169 | switch (type) { | 1152 | switch (type) { |
| 1170 | case hwmon_power: | 1153 | case hwmon_power: |
| 1171 | ret = xe_hwmon_power_write(hwmon, attr, channel, val); | 1154 | return xe_hwmon_power_write(hwmon, attr, channel, val); |
| 1172 | break; | ||
| 1173 | case hwmon_curr: | 1155 | case hwmon_curr: |
| 1174 | ret = xe_hwmon_curr_write(hwmon, attr, channel, val); | 1156 | return xe_hwmon_curr_write(hwmon, attr, channel, val); |
| 1175 | break; | ||
| 1176 | default: | 1157 | default: |
| 1177 | ret = -EOPNOTSUPP; | 1158 | return -EOPNOTSUPP; |
| 1178 | break; | ||
| 1179 | } | 1159 | } |
| 1180 | |||
| 1181 | xe_pm_runtime_put(hwmon->xe); | ||
| 1182 | |||
| 1183 | return ret; | ||
| 1184 | } | 1160 | } |
| 1185 | 1161 | ||
| 1186 | static int xe_hwmon_read_label(struct device *dev, | 1162 | static int xe_hwmon_read_label(struct device *dev, |
| @@ -319,7 +319,7 @@ int xe_i2c_probe(struct xe_device *xe) · 318 unmodified lines | |||
| 319 | struct xe_i2c *i2c; | 319 | struct xe_i2c *i2c; |
| 320 | int ret; | 320 | int ret; |
| 321 | 321 | ||
| 322 | if (xe->info.platform != XE_BATTLEMAGE) | 322 | if (!xe->info.has_i2c) |
| 323 | return 0; | 323 | return 0; |
| 324 | 324 | ||
| 325 | if (IS_SRIOV_VF(xe)) | 325 | if (IS_SRIOV_VF(xe)) |
| @@ -21,6 +21,7 @@ · 20 unmodified lines | |||
| 21 | #include "xe_hw_error.h" | 21 | #include "xe_hw_error.h" |
| 22 | #include "xe_i2c.h" | 22 | #include "xe_i2c.h" |
| 23 | #include "xe_memirq.h" | 23 | #include "xe_memirq.h" |
| 24 | #include "xe_mert.h" | ||
| 24 | #include "xe_mmio.h" | 25 | #include "xe_mmio.h" |
| 25 | #include "xe_pxp.h" | 26 | #include "xe_pxp.h" |
| 26 | #include "xe_sriov.h" | 27 | #include "xe_sriov.h" |
| @@ -525,6 +526,7 @@ static irqreturn_t dg1_irq_handler(int irq, void *arg) · 498 unmodified lines | |||
| 525 | xe_heci_csc_irq_handler(xe, master_ctl); | 526 | xe_heci_csc_irq_handler(xe, master_ctl); |
| 526 | xe_display_irq_handler(xe, master_ctl); | 527 | xe_display_irq_handler(xe, master_ctl); |
| 527 | xe_i2c_irq_handler(xe, master_ctl); | 528 | xe_i2c_irq_handler(xe, master_ctl); |
| 529 | xe_mert_irq_handler(xe, master_ctl); | ||
| 528 | gu_misc_iir = gu_misc_irq_ack(xe, master_ctl); | 530 | gu_misc_iir = gu_misc_irq_ack(xe, master_ctl); |
| 529 | } | 531 | } |
| 530 | } | 532 | } |
| @@ -8,15 +8,18 @@ · 7 unmodified lines | |||
| 8 | #include <drm/drm_managed.h> | 8 | #include <drm/drm_managed.h> |
| 9 | 9 | ||
| 10 | #include "regs/xe_gt_regs.h" | 10 | #include "regs/xe_gt_regs.h" |
| 11 | #include "regs/xe_mert_regs.h" | ||
| 11 | 12 | ||
| 12 | #include "xe_assert.h" | 13 | #include "xe_assert.h" |
| 13 | #include "xe_bo.h" | 14 | #include "xe_bo.h" |
| 14 | #include "xe_tlb_inval.h" | 15 | #include "xe_tlb_inval.h" |
| 15 | #include "xe_lmtt.h" | 16 | #include "xe_lmtt.h" |
| 16 | #include "xe_map.h" | 17 | #include "xe_map.h" |
| 18 | #include "xe_mert.h" | ||
| 17 | #include "xe_mmio.h" | 19 | #include "xe_mmio.h" |
| 18 | #include "xe_res_cursor.h" | 20 | #include "xe_res_cursor.h" |
| 19 | #include "xe_sriov.h" | 21 | #include "xe_sriov.h" |
| 22 | #include "xe_tile.h" | ||
| 20 | #include "xe_tile_sriov_printk.h" | 23 | #include "xe_tile_sriov_printk.h" |
| 21 | 24 | ||
| 22 | /** | 25 | /** |
| @@ -196,16 +199,22 @@ static void lmtt_setup_dir_ptr(struct xe_lmtt *lmtt) · 173 unmodified lines | |||
| 196 | struct xe_device *xe = tile_to_xe(tile); | 199 | struct xe_device *xe = tile_to_xe(tile); |
| 197 | dma_addr_t offset = xe_bo_main_addr(lmtt->pd->bo, XE_PAGE_SIZE); | 200 | dma_addr_t offset = xe_bo_main_addr(lmtt->pd->bo, XE_PAGE_SIZE); |
| 198 | struct xe_gt *gt; | 201 | struct xe_gt *gt; |
| 202 | u32 config; | ||
| 199 | u8 id; | 203 | u8 id; |
| 200 | 204 | ||
| 201 | lmtt_debug(lmtt, "DIR offset %pad\n", &offset); | 205 | lmtt_debug(lmtt, "DIR offset %pad\n", &offset); |
| 202 | lmtt_assert(lmtt, xe_bo_is_vram(lmtt->pd->bo)); | 206 | lmtt_assert(lmtt, xe_bo_is_vram(lmtt->pd->bo)); |
| 203 | lmtt_assert(lmtt, IS_ALIGNED(offset, SZ_64K)); | 207 | lmtt_assert(lmtt, IS_ALIGNED(offset, SZ_64K)); |
| 204 | 208 | ||
| 209 | config = LMEM_EN | REG_FIELD_PREP(LMTT_DIR_PTR, offset / SZ_64K); | ||
| 210 | |||
| 205 | for_each_gt_on_tile(gt, tile, id) | 211 | for_each_gt_on_tile(gt, tile, id) |
| 206 | xe_mmio_write32(>->mmio, | 212 | xe_mmio_write32(>->mmio, |
| 207 | GRAPHICS_VER(xe) >= 20 ? XE2_LMEM_CFG : LMEM_CFG, | 213 | GRAPHICS_VER(xe) >= 20 ? XE2_LMEM_CFG : LMEM_CFG, |
| 208 | LMEM_EN | REG_FIELD_PREP(LMTT_DIR_PTR, offset / SZ_64K)); | 214 | config); |
| 215 | |||
| 216 | if (xe_device_has_mert(xe) && xe_tile_is_root(tile)) | ||
| 217 | xe_mmio_write32(&tile->mmio, MERT_LMEM_CFG, config); | ||
| 209 | } | 218 | } |
| 210 | 219 | ||
| 211 | /** | 220 | /** |
| @@ -262,19 +271,29 @@ static int lmtt_invalidate_hw(struct xe_lmtt *lmtt) · 50 unmodified lines | |||
| 262 | * @lmtt: the &xe_lmtt to invalidate | 271 | * @lmtt: the &xe_lmtt to invalidate |
| 263 | * | 272 | * |
| 264 | * Send requests to all GuCs on this tile to invalidate all TLBs. | 273 | * Send requests to all GuCs on this tile to invalidate all TLBs. |
| 274 | * If the platform has a standalone MERT, also invalidate MERT's TLB. | ||
| 265 | * | 275 | * |
| 266 | * This function should be called only when running as a PF driver. | 276 | * This function should be called only when running as a PF driver. |
| 267 | */ | 277 | */ |
| 268 | void xe_lmtt_invalidate_hw(struct xe_lmtt *lmtt) | 278 | void xe_lmtt_invalidate_hw(struct xe_lmtt *lmtt) |
| 269 | { | 279 | { |
| 280 | struct xe_tile *tile = lmtt_to_tile(lmtt); | ||
| 281 | struct xe_device *xe = lmtt_to_xe(lmtt); | ||
| 270 | int err; | 282 | int err; |
| 271 | 283 | ||
| 272 | lmtt_assert(lmtt, IS_SRIOV_PF(lmtt_to_xe(lmtt))); | 284 | lmtt_assert(lmtt, IS_SRIOV_PF(xe)); |
| 273 | 285 | ||
| 274 | err = lmtt_invalidate_hw(lmtt); | 286 | err = lmtt_invalidate_hw(lmtt); |
| 275 | if (err) | 287 | if (err) |
| 276 | xe_tile_sriov_err(lmtt_to_tile(lmtt), "LMTT invalidation failed (%pe)", | 288 | xe_tile_sriov_err(tile, "LMTT invalidation failed (%pe)", |
| 277 | ERR_PTR(err)); | 289 | ERR_PTR(err)); |
| 290 | |||
| 291 | if (xe_device_has_mert(xe) && xe_tile_is_root(tile)) { | ||
| 292 | err = xe_mert_invalidate_lmtt(tile); | ||
| 293 | if (err) | ||
| 294 | xe_tile_sriov_err(tile, "MERT LMTT invalidation failed (%pe)", | ||
| 295 | ERR_PTR(err)); | ||
| 296 | } | ||
| 278 | } | 297 | } |
| 279 | 298 | ||
| 280 | static void lmtt_write_pte(struct xe_lmtt *lmtt, struct xe_lmtt_pt *pt, | 299 | static void lmtt_write_pte(struct xe_lmtt *lmtt, struct xe_lmtt_pt *pt, |
| @@ -44,6 +44,11 @@ · 43 unmodified lines | |||
| 44 | #define LRC_INDIRECT_CTX_BO_SIZE SZ_4K | 44 | #define LRC_INDIRECT_CTX_BO_SIZE SZ_4K |
| 45 | #define LRC_INDIRECT_RING_STATE_SIZE SZ_4K | 45 | #define LRC_INDIRECT_RING_STATE_SIZE SZ_4K |
| 46 | 46 | ||
| 47 | #define LRC_PRIORITY GENMASK_ULL(10, 9) | ||
| 48 | #define LRC_PRIORITY_LOW 0 | ||
| 49 | #define LRC_PRIORITY_NORMAL 1 | ||
| 50 | #define LRC_PRIORITY_HIGH 2 | ||
| 51 | |||
| 47 | /* | 52 | /* |
| 48 | * Layout of the LRC and associated data allocated as | 53 | * Layout of the LRC and associated data allocated as |
| 49 | * lrc->bo: | 54 | * lrc->bo: |
| @@ -91,13 +96,19 @@ gt_engine_needs_indirect_ctx(struct xe_gt *gt, enum xe_engine_class class) · 41 unmodified lines | |||
| 91 | return false; | 96 | return false; |
| 92 | } | 97 | } |
| 93 | 98 | ||
| 94 | size_t xe_gt_lrc_size(struct xe_gt *gt, enum xe_engine_class class) | 99 | /** |
| 100 | * xe_gt_lrc_hang_replay_size() - Hang replay size | ||
| 101 | * @gt: The GT | ||
| 102 | * @class: Hardware engine class | ||
| 103 | * | ||
| 104 | * Determine size of GPU hang replay state for a GT and hardware engine class. | ||
| 105 | * | ||
| 106 | * Return: Size of GPU hang replay size | ||
| 107 | */ | ||
| 108 | size_t xe_gt_lrc_hang_replay_size(struct xe_gt *gt, enum xe_engine_class class) | ||
| 95 | { | 109 | { |
| 96 | struct xe_device *xe = gt_to_xe(gt); | 110 | struct xe_device *xe = gt_to_xe(gt); |
| 97 | size_t size; | 111 | size_t size = 0; |
| 98 | |||
| 99 | /* Per-process HW status page (PPHWSP) */ | ||
| 100 | size = LRC_PPHWSP_SIZE; | ||
| 101 | 112 | ||
| 102 | /* Engine context image */ | 113 | /* Engine context image */ |
| 103 | switch (class) { | 114 | switch (class) { |
| @@ -123,11 +134,18 @@ size_t xe_gt_lrc_size(struct xe_gt *gt, enum xe_engine_class class) · 19 unmodified lines | |||
| 123 | size += 1 * SZ_4K; | 134 | size += 1 * SZ_4K; |
| 124 | } | 135 | } |
| 125 | 136 | ||
| 137 | return size; | ||
| 138 | } | ||
| 139 | |||
| 140 | size_t xe_gt_lrc_size(struct xe_gt *gt, enum xe_engine_class class) | ||
| 141 | { | ||
| 142 | size_t size = xe_gt_lrc_hang_replay_size(gt, class); | ||
| 143 | |||
| 126 | /* Add indirect ring state page */ | 144 | /* Add indirect ring state page */ |
| 127 | if (xe_gt_has_indirect_ring_state(gt)) | 145 | if (xe_gt_has_indirect_ring_state(gt)) |
| 128 | size += LRC_INDIRECT_RING_STATE_SIZE; | 146 | size += LRC_INDIRECT_RING_STATE_SIZE; |
| 129 | 147 | ||
| 130 | return size; | 148 | return size + LRC_PPHWSP_SIZE; |
| 131 | } | 149 | } |
| 132 | 150 | ||
| 133 | /* | 151 | /* |
| @@ -1386,8 +1404,33 @@ setup_indirect_ctx(struct xe_lrc *lrc, struct xe_hw_engine *hwe) · 1252 unmodified lines | |||
| 1386 | return 0; | 1404 | return 0; |
| 1387 | } | 1405 | } |
| 1388 | 1406 | ||
| 1407 | static u8 xe_multi_queue_prio_to_lrc(struct xe_lrc *lrc, enum xe_multi_queue_priority priority) | ||
| 1408 | { | ||
| 1409 | struct xe_device *xe = gt_to_xe(lrc->gt); | ||
| 1410 | |||
| 1411 | xe_assert(xe, (priority >= XE_MULTI_QUEUE_PRIORITY_LOW && | ||
| 1412 | priority <= XE_MULTI_QUEUE_PRIORITY_HIGH)); | ||
| 1413 | |||
| 1414 | /* xe_multi_queue_priority is directly mapped to LRC priority values */ | ||
| 1415 | return priority; | ||
| 1416 | } | ||
| 1417 | |||
| 1418 | /** | ||
| 1419 | * xe_lrc_set_multi_queue_priority() - Set multi queue priority in LRC | ||
| 1420 | * @lrc: Logical Ring Context | ||
| 1421 | * @priority: Multi queue priority of the exec queue | ||
| 1422 | * | ||
| 1423 | * Convert @priority to LRC multi queue priority and update the @lrc descriptor | ||
| 1424 | */ | ||
| 1425 | void xe_lrc_set_multi_queue_priority(struct xe_lrc *lrc, enum xe_multi_queue_priority priority) | ||
| 1426 | { | ||
| 1427 | lrc->desc &= ~LRC_PRIORITY; | ||
| 1428 | lrc->desc |= FIELD_PREP(LRC_PRIORITY, xe_multi_queue_prio_to_lrc(lrc, priority)); | ||
| 1429 | } | ||
| 1430 | |||
| 1389 | static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, | 1431 | static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, |
| 1390 | struct xe_vm *vm, u32 ring_size, u16 msix_vec, | 1432 | struct xe_vm *vm, void *replay_state, u32 ring_size, |
| 1433 | u16 msix_vec, | ||
| 1391 | u32 init_flags) | 1434 | u32 init_flags) |
| 1392 | { | 1435 | { |
| 1393 | struct xe_gt *gt = hwe->gt; | 1436 | struct xe_gt *gt = hwe->gt; |
| @@ -1402,6 +1445,7 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, · 8 unmodified lines | |||
| 1402 | 1445 | ||
| 1403 | kref_init(&lrc->refcount); | 1446 | kref_init(&lrc->refcount); |
| 1404 | lrc->gt = gt; | 1447 | lrc->gt = gt; |
| 1448 | lrc->replay_size = xe_gt_lrc_hang_replay_size(gt, hwe->class); | ||
| 1405 | lrc->size = lrc_size; | 1449 | lrc->size = lrc_size; |
| 1406 | lrc->flags = 0; | 1450 | lrc->flags = 0; |
| 1407 | lrc->ring.size = ring_size; | 1451 | lrc->ring.size = ring_size; |
| @@ -1438,11 +1482,14 @@ static int xe_lrc_init(struct xe_lrc *lrc, struct xe_hw_engine *hwe, · 30 unmodified lines | |||
| 1438 | * scratch. | 1482 | * scratch. |
| 1439 | */ | 1483 | */ |
| 1440 | map = __xe_lrc_pphwsp_map(lrc); | 1484 | map = __xe_lrc_pphwsp_map(lrc); |
| 1441 | if (gt->default_lrc[hwe->class]) { | 1485 | if (gt->default_lrc[hwe->class] || replay_state) { |
| 1442 | xe_map_memset(xe, &map, 0, 0, LRC_PPHWSP_SIZE); /* PPHWSP */ | 1486 | xe_map_memset(xe, &map, 0, 0, LRC_PPHWSP_SIZE); /* PPHWSP */ |
| 1443 | xe_map_memcpy_to(xe, &map, LRC_PPHWSP_SIZE, | 1487 | xe_map_memcpy_to(xe, &map, LRC_PPHWSP_SIZE, |
| 1444 | gt->default_lrc[hwe->class] + LRC_PPHWSP_SIZE, | 1488 | gt->default_lrc[hwe->class] + LRC_PPHWSP_SIZE, |
| 1445 | lrc_size - LRC_PPHWSP_SIZE); | 1489 | lrc_size - LRC_PPHWSP_SIZE); |
| 1490 | if (replay_state) | ||
| 1491 | xe_map_memcpy_to(xe, &map, LRC_PPHWSP_SIZE, | ||
| 1492 | replay_state, lrc->replay_size); | ||
| 1446 | } else { | 1493 | } else { |
| 1447 | void *init_data = empty_lrc_data(hwe); | 1494 | void *init_data = empty_lrc_data(hwe); |
| 1448 | 1495 | ||
| @@ -1550,6 +1597,7 @@ err_lrc_finish: · 101 unmodified lines | |||
| 1550 | * xe_lrc_create - Create a LRC | 1597 | * xe_lrc_create - Create a LRC |
| 1551 | * @hwe: Hardware Engine | 1598 | * @hwe: Hardware Engine |
| 1552 | * @vm: The VM (address space) | 1599 | * @vm: The VM (address space) |
| 1600 | * @replay_state: GPU hang replay state | ||
| 1553 | * @ring_size: LRC ring size | 1601 | * @ring_size: LRC ring size |
| 1554 | * @msix_vec: MSI-X interrupt vector (for platforms that support it) | 1602 | * @msix_vec: MSI-X interrupt vector (for platforms that support it) |
| 1555 | * @flags: LRC initialization flags | 1603 | * @flags: LRC initialization flags |
| @@ -1560,7 +1608,7 @@ err_lrc_finish: · 4 unmodified lines | |||
| 1560 | * upon failure. | 1608 | * upon failure. |
| 1561 | */ | 1609 | */ |
| 1562 | struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, | 1610 | struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, |
| 1563 | u32 ring_size, u16 msix_vec, u32 flags) | 1611 | void *replay_state, u32 ring_size, u16 msix_vec, u32 flags) |
| 1564 | { | 1612 | { |
| 1565 | struct xe_lrc *lrc; | 1613 | struct xe_lrc *lrc; |
| 1566 | int err; | 1614 | int err; |
| @@ -1569,7 +1617,7 @@ struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, · 2 unmodified lines | |||
| 1569 | if (!lrc) | 1617 | if (!lrc) |
| 1570 | return ERR_PTR(-ENOMEM); | 1618 | return ERR_PTR(-ENOMEM); |
| 1571 | 1619 | ||
| 1572 | err = xe_lrc_init(lrc, hwe, vm, ring_size, msix_vec, flags); | 1620 | err = xe_lrc_init(lrc, hwe, vm, replay_state, ring_size, msix_vec, flags); |
| 1573 | if (err) { | 1621 | if (err) { |
| 1574 | kfree(lrc); | 1622 | kfree(lrc); |
| 1575 | return ERR_PTR(err); | 1623 | return ERR_PTR(err); |
| @@ -2235,6 +2283,8 @@ struct xe_lrc_snapshot *xe_lrc_snapshot_capture(struct xe_lrc *lrc) · 659 unmodified lines | |||
| 2235 | snapshot->lrc_bo = xe_bo_get(lrc->bo); | 2283 | snapshot->lrc_bo = xe_bo_get(lrc->bo); |
| 2236 | snapshot->lrc_offset = xe_lrc_pphwsp_offset(lrc); | 2284 | snapshot->lrc_offset = xe_lrc_pphwsp_offset(lrc); |
| 2237 | snapshot->lrc_size = lrc->size; | 2285 | snapshot->lrc_size = lrc->size; |
| 2286 | snapshot->replay_offset = 0; | ||
| 2287 | snapshot->replay_size = lrc->replay_size; | ||
| 2238 | snapshot->lrc_snapshot = NULL; | 2288 | snapshot->lrc_snapshot = NULL; |
| 2239 | snapshot->ctx_timestamp = lower_32_bits(xe_lrc_ctx_timestamp(lrc)); | 2289 | snapshot->ctx_timestamp = lower_32_bits(xe_lrc_ctx_timestamp(lrc)); |
| 2240 | snapshot->ctx_job_timestamp = xe_lrc_ctx_job_timestamp(lrc); | 2290 | snapshot->ctx_job_timestamp = xe_lrc_ctx_job_timestamp(lrc); |
| @@ -2305,6 +2355,9 @@ void xe_lrc_snapshot_print(struct xe_lrc_snapshot *snapshot, struct drm_printer · 64 unmodified lines | |||
| 2305 | } | 2355 | } |
| 2306 | 2356 | ||
| 2307 | drm_printf(p, "\n\t[HWCTX].length: 0x%lx\n", snapshot->lrc_size - LRC_PPHWSP_SIZE); | 2357 | drm_printf(p, "\n\t[HWCTX].length: 0x%lx\n", snapshot->lrc_size - LRC_PPHWSP_SIZE); |
| 2358 | drm_printf(p, "\n\t[HWCTX].replay_offset: 0x%lx\n", snapshot->replay_offset); | ||
| 2359 | drm_printf(p, "\n\t[HWCTX].replay_length: 0x%lx\n", snapshot->replay_size); | ||
| 2360 | |||
| 2308 | drm_puts(p, "\t[HWCTX].data: "); | 2361 | drm_puts(p, "\t[HWCTX].data: "); |
| 2309 | for (; i < snapshot->lrc_size; i += sizeof(u32)) { | 2362 | for (; i < snapshot->lrc_size; i += sizeof(u32)) { |
| 2310 | u32 *val = snapshot->lrc_snapshot + i; | 2363 | u32 *val = snapshot->lrc_snapshot + i; |
| @@ -13,6 +13,7 @@ struct drm_printer; · 12 unmodified lines | |||
| 13 | struct xe_bb; | 13 | struct xe_bb; |
| 14 | struct xe_device; | 14 | struct xe_device; |
| 15 | struct xe_exec_queue; | 15 | struct xe_exec_queue; |
| 16 | enum xe_multi_queue_priority; | ||
| 16 | enum xe_engine_class; | 17 | enum xe_engine_class; |
| 17 | struct xe_gt; | 18 | struct xe_gt; |
| 18 | struct xe_hw_engine; | 19 | struct xe_hw_engine; |
| @@ -23,6 +24,7 @@ struct xe_lrc_snapshot { · 4 unmodified lines | |||
| 23 | struct xe_bo *lrc_bo; | 24 | struct xe_bo *lrc_bo; |
| 24 | void *lrc_snapshot; | 25 | void *lrc_snapshot; |
| 25 | unsigned long lrc_size, lrc_offset; | 26 | unsigned long lrc_size, lrc_offset; |
| 27 | unsigned long replay_size, replay_offset; | ||
| 26 | 28 | ||
| 27 | u32 context_desc; | 29 | u32 context_desc; |
| 28 | u32 ring_addr; | 30 | u32 ring_addr; |
| @@ -49,7 +51,7 @@ struct xe_lrc_snapshot { · 20 unmodified lines | |||
| 49 | #define XE_LRC_CREATE_USER_CTX BIT(2) | 51 | #define XE_LRC_CREATE_USER_CTX BIT(2) |
| 50 | 52 | ||
| 51 | struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, | 53 | struct xe_lrc *xe_lrc_create(struct xe_hw_engine *hwe, struct xe_vm *vm, |
| 52 | u32 ring_size, u16 msix_vec, u32 flags); | 54 | void *replay_state, u32 ring_size, u16 msix_vec, u32 flags); |
| 53 | void xe_lrc_destroy(struct kref *ref); | 55 | void xe_lrc_destroy(struct kref *ref); |
| 54 | 56 | ||
| 55 | /** | 57 | /** |
| @@ -86,6 +88,7 @@ static inline size_t xe_lrc_ring_size(void) · 30 unmodified lines | |||
| 86 | return SZ_16K; | 88 | return SZ_16K; |
| 87 | } | 89 | } |
| 88 | 90 | ||
| 91 | size_t xe_gt_lrc_hang_replay_size(struct xe_gt *gt, enum xe_engine_class class); | ||
| 89 | size_t xe_gt_lrc_size(struct xe_gt *gt, enum xe_engine_class class); | 92 | size_t xe_gt_lrc_size(struct xe_gt *gt, enum xe_engine_class class); |
| 90 | u32 xe_lrc_pphwsp_offset(struct xe_lrc *lrc); | 93 | u32 xe_lrc_pphwsp_offset(struct xe_lrc *lrc); |
| 91 | u32 xe_lrc_regs_offset(struct xe_lrc *lrc); | 94 | u32 xe_lrc_regs_offset(struct xe_lrc *lrc); |
| @@ -133,6 +136,8 @@ void xe_lrc_dump_default(struct drm_printer *p, · 41 unmodified lines | |||
| 133 | 136 | ||
| 134 | u32 *xe_lrc_emit_hwe_state_instructions(struct xe_exec_queue *q, u32 *cs); | 137 | u32 *xe_lrc_emit_hwe_state_instructions(struct xe_exec_queue *q, u32 *cs); |
| 135 | 138 | ||
| 139 | void xe_lrc_set_multi_queue_priority(struct xe_lrc *lrc, enum xe_multi_queue_priority priority); | ||
| 140 | |||
| 136 | struct xe_lrc_snapshot *xe_lrc_snapshot_capture(struct xe_lrc *lrc); | 141 | struct xe_lrc_snapshot *xe_lrc_snapshot_capture(struct xe_lrc *lrc); |
| 137 | void xe_lrc_snapshot_capture_delayed(struct xe_lrc_snapshot *snapshot); | 142 | void xe_lrc_snapshot_capture_delayed(struct xe_lrc_snapshot *snapshot); |
| 138 | void xe_lrc_snapshot_print(struct xe_lrc_snapshot *snapshot, struct drm_printer *p); | 143 | void xe_lrc_snapshot_print(struct xe_lrc_snapshot *snapshot, struct drm_printer *p); |
| @@ -25,6 +25,9 @@ struct xe_lrc { · 24 unmodified lines | |||
| 25 | /** @size: size of the lrc and optional indirect ring state */ | 25 | /** @size: size of the lrc and optional indirect ring state */ |
| 26 | u32 size; | 26 | u32 size; |
| 27 | 27 | ||
| 28 | /** @replay_size: Size LRC needed for replaying a hang */ | ||
| 29 | u32 replay_size; | ||
| 30 | |||
| 28 | /** @gt: gt which this LRC belongs to */ | 31 | /** @gt: gt which this LRC belongs to */ |
| 29 | struct xe_gt *gt; | 32 | struct xe_gt *gt; |
| 30 | 33 | ||
| @@ -0,0 +1,82 @@ | |||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | /* | ||
| 3 | * Copyright(c) 2025, Intel Corporation. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include "regs/xe_irq_regs.h" | ||
| 7 | #include "regs/xe_mert_regs.h" | ||
| 8 | |||
| 9 | #include "xe_device.h" | ||
| 10 | #include "xe_mert.h" | ||
| 11 | #include "xe_mmio.h" | ||
| 12 | #include "xe_tile.h" | ||
| 13 | |||
| 14 | /** | ||
| 15 | * xe_mert_invalidate_lmtt - Invalidate MERT LMTT | ||
| 16 | * @tile: the &xe_tile | ||
| 17 | * | ||
| 18 | * Trigger invalidation of the MERT LMTT and wait for completion. | ||
| 19 | * | ||
| 20 | * Return: 0 on success or -ETIMEDOUT in case of a timeout. | ||
| 21 | */ | ||
| 22 | int xe_mert_invalidate_lmtt(struct xe_tile *tile) | ||
| 23 | { | ||
| 24 | struct xe_device *xe = tile_to_xe(tile); | ||
| 25 | struct xe_mert *mert = &tile->mert; | ||
| 26 | const long timeout = HZ / 4; | ||
| 27 | unsigned long flags; | ||
| 28 | |||
| 29 | xe_assert(xe, xe_device_has_mert(xe)); | ||
| 30 | xe_assert(xe, xe_tile_is_root(tile)); | ||
| 31 | |||
| 32 | spin_lock_irqsave(&mert->lock, flags); | ||
| 33 | if (!mert->tlb_inv_triggered) { | ||
| 34 | mert->tlb_inv_triggered = true; | ||
| 35 | reinit_completion(&mert->tlb_inv_done); | ||
| 36 | xe_mmio_write32(&tile->mmio, MERT_TLB_INV_DESC_A, MERT_TLB_INV_DESC_A_VALID); | ||
| 37 | } | ||
| 38 | spin_unlock_irqrestore(&mert->lock, flags); | ||
| 39 | |||
| 40 | if (!wait_for_completion_timeout(&mert->tlb_inv_done, timeout)) | ||
| 41 | return -ETIMEDOUT; | ||
| 42 | |||
| 43 | return 0; | ||
| 44 | } | ||
| 45 | |||
| 46 | /** | ||
| 47 | * xe_mert_irq_handler - Handler for MERT interrupts | ||
| 48 | * @xe: the &xe_device | ||
| 49 | * @master_ctl: interrupt register | ||
| 50 | * | ||
| 51 | * Handle interrupts generated by MERT. | ||
| 52 | */ | ||
| 53 | void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl) | ||
| 54 | { | ||
| 55 | struct xe_tile *tile = xe_device_get_root_tile(xe); | ||
| 56 | unsigned long flags; | ||
| 57 | u32 reg_val; | ||
| 58 | u8 err; | ||
| 59 | |||
| 60 | if (!(master_ctl & SOC_H2DMEMINT_IRQ)) | ||
| 61 | return; | ||
| 62 | |||
| 63 | reg_val = xe_mmio_read32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT); | ||
| 64 | xe_mmio_write32(&tile->mmio, MERT_TLB_CT_INTR_ERR_ID_PORT, 0); | ||
| 65 | |||
| 66 | err = FIELD_GET(MERT_TLB_CT_ERROR_MASK, reg_val); | ||
| 67 | if (err == MERT_TLB_CT_LMTT_FAULT) | ||
| 68 | drm_dbg(&xe->drm, "MERT catastrophic error: LMTT fault (VF%u)\n", | ||
| 69 | FIELD_GET(MERT_TLB_CT_VFID_MASK, reg_val)); | ||
| 70 | else if (err) | ||
| 71 | drm_dbg(&xe->drm, "MERT catastrophic error: Unexpected fault (0x%x)\n", err); | ||
| 72 | |||
| 73 | spin_lock_irqsave(&tile->mert.lock, flags); | ||
| 74 | if (tile->mert.tlb_inv_triggered) { | ||
| 75 | reg_val = xe_mmio_read32(&tile->mmio, MERT_TLB_INV_DESC_A); | ||
| 76 | if (!(reg_val & MERT_TLB_INV_DESC_A_VALID)) { | ||
| 77 | tile->mert.tlb_inv_triggered = false; | ||
| 78 | complete_all(&tile->mert.tlb_inv_done); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | spin_unlock_irqrestore(&tile->mert.lock, flags); | ||
| 82 | } | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | /* | ||
| 3 | * Copyright(c) 2025, Intel Corporation. All rights reserved. | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef __XE_MERT_H__ | ||
| 7 | #define __XE_MERT_H__ | ||
| 8 | |||
| 9 | #include <linux/completion.h> | ||
| 10 | #include <linux/spinlock.h> | ||
| 11 | #include <linux/types.h> | ||
| 12 | |||
| 13 | struct xe_device; | ||
| 14 | struct xe_tile; | ||
| 15 | |||
| 16 | struct xe_mert { | ||
| 17 | /** @lock: protects the TLB invalidation status */ | ||
| 18 | spinlock_t lock; | ||
| 19 | /** @tlb_inv_triggered: indicates if TLB invalidation was triggered */ | ||
| 20 | bool tlb_inv_triggered; | ||
| 21 | /** @mert.tlb_inv_done: completion of TLB invalidation */ | ||
| 22 | struct completion tlb_inv_done; | ||
| 23 | }; | ||
| 24 | |||
| 25 | #ifdef CONFIG_PCI_IOV | ||
| 26 | int xe_mert_invalidate_lmtt(struct xe_tile *tile); | ||
| 27 | void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl); | ||
| 28 | #else | ||
| 29 | static inline void xe_mert_irq_handler(struct xe_device *xe, u32 master_ctl) { } | ||
| 30 | #endif | ||
| 31 | |||
| 32 | #endif /* __XE_MERT_H__ */ | ||
| @@ -34,6 +34,7 @@ · 33 unmodified lines | |||
| 34 | #include "xe_res_cursor.h" | 34 | #include "xe_res_cursor.h" |
| 35 | #include "xe_sa.h" | 35 | #include "xe_sa.h" |
| 36 | #include "xe_sched_job.h" | 36 | #include "xe_sched_job.h" |
| 37 | #include "xe_sriov_vf_ccs.h" | ||
| 37 | #include "xe_sync.h" | 38 | #include "xe_sync.h" |
| 38 | #include "xe_trace_bo.h" | 39 | #include "xe_trace_bo.h" |
| 39 | #include "xe_validation.h" | 40 | #include "xe_validation.h" |
| @@ -1103,12 +1104,16 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, · 1063 unmodified lines | |||
| 1103 | u32 batch_size, batch_size_allocated; | 1104 | u32 batch_size, batch_size_allocated; |
| 1104 | struct xe_device *xe = gt_to_xe(gt); | 1105 | struct xe_device *xe = gt_to_xe(gt); |
| 1105 | struct xe_res_cursor src_it, ccs_it; | 1106 | struct xe_res_cursor src_it, ccs_it; |
| 1107 | struct xe_sriov_vf_ccs_ctx *ctx; | ||
| 1108 | struct xe_sa_manager *bb_pool; | ||
| 1106 | u64 size = xe_bo_size(src_bo); | 1109 | u64 size = xe_bo_size(src_bo); |
| 1107 | struct xe_bb *bb = NULL; | 1110 | struct xe_bb *bb = NULL; |
| 1108 | u64 src_L0, src_L0_ofs; | 1111 | u64 src_L0, src_L0_ofs; |
| 1109 | u32 src_L0_pt; | 1112 | u32 src_L0_pt; |
| 1110 | int err; | 1113 | int err; |
| 1111 | 1114 | ||
| 1115 | ctx = &xe->sriov.vf.ccs.contexts[read_write]; | ||
| 1116 | |||
| 1112 | xe_res_first_sg(xe_bo_sg(src_bo), 0, size, &src_it); | 1117 | xe_res_first_sg(xe_bo_sg(src_bo), 0, size, &src_it); |
| 1113 | 1118 | ||
| 1114 | xe_res_first_sg(xe_bo_sg(src_bo), xe_bo_ccs_pages_start(src_bo), | 1119 | xe_res_first_sg(xe_bo_sg(src_bo), xe_bo_ccs_pages_start(src_bo), |
| @@ -1141,11 +1146,15 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, · 26 unmodified lines | |||
| 1141 | size -= src_L0; | 1146 | size -= src_L0; |
| 1142 | } | 1147 | } |
| 1143 | 1148 | ||
| 1149 | bb_pool = ctx->mem.ccs_bb_pool; | ||
| 1150 | guard(mutex) (xe_sa_bo_swap_guard(bb_pool)); | ||
| 1151 | xe_sa_bo_swap_shadow(bb_pool); | ||
| 1152 | |||
| 1144 | bb = xe_bb_ccs_new(gt, batch_size, read_write); | 1153 | bb = xe_bb_ccs_new(gt, batch_size, read_write); |
| 1145 | if (IS_ERR(bb)) { | 1154 | if (IS_ERR(bb)) { |
| 1146 | drm_err(&xe->drm, "BB allocation failed.\n"); | 1155 | drm_err(&xe->drm, "BB allocation failed.\n"); |
| 1147 | err = PTR_ERR(bb); | 1156 | err = PTR_ERR(bb); |
| 1148 | goto err_ret; | 1157 | return err; |
| 1149 | } | 1158 | } |
| 1150 | 1159 | ||
| 1151 | batch_size_allocated = batch_size; | 1160 | batch_size_allocated = batch_size; |
| @@ -1194,10 +1203,52 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, · 42 unmodified lines | |||
| 1194 | xe_assert(xe, (batch_size_allocated == bb->len)); | 1203 | xe_assert(xe, (batch_size_allocated == bb->len)); |
| 1195 | src_bo->bb_ccs[read_write] = bb; | 1204 | src_bo->bb_ccs[read_write] = bb; |
| 1196 | 1205 | ||
| 1206 | xe_sriov_vf_ccs_rw_update_bb_addr(ctx); | ||
| 1207 | xe_sa_bo_sync_shadow(bb->bo); | ||
| 1197 | return 0; | 1208 | return 0; |
| 1209 | } | ||
| 1198 | 1210 | ||
| 1199 | err_ret: | 1211 | /** |
| 1200 | return err; | 1212 | * xe_migrate_ccs_rw_copy_clear() - Clear the CCS read/write batch buffer |
| 1213 | * content. | ||
| 1214 | * @src_bo: The buffer object @src is currently bound to. | ||
| 1215 | * @read_write : Creates BB commands for CCS read/write. | ||
| 1216 | * | ||
| 1217 | * Directly clearing the BB lacks atomicity and can lead to undefined | ||
| 1218 | * behavior if the vCPU is halted mid-operation during the clearing | ||
| 1219 | * process. To avoid this issue, we use a shadow buffer object approach. | ||
| 1220 | * | ||
| 1221 | * First swap the SA BO address with the shadow BO, perform the clearing | ||
| 1222 | * operation on the BB, update the shadow BO in the ring buffer, then | ||
| 1223 | * sync the shadow and the actual buffer to maintain consistency. | ||
| 1224 | * | ||
| 1225 | * Returns: None. | ||
| 1226 | */ | ||
| 1227 | void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo, | ||
| 1228 | enum xe_sriov_vf_ccs_rw_ctxs read_write) | ||
| 1229 | { | ||
| 1230 | struct xe_bb *bb = src_bo->bb_ccs[read_write]; | ||
| 1231 | struct xe_device *xe = xe_bo_device(src_bo); | ||
| 1232 | struct xe_sriov_vf_ccs_ctx *ctx; | ||
| 1233 | struct xe_sa_manager *bb_pool; | ||
| 1234 | u32 *cs; | ||
| 1235 | |||
| 1236 | xe_assert(xe, IS_SRIOV_VF(xe)); | ||
| 1237 | |||
| 1238 | ctx = &xe->sriov.vf.ccs.contexts[read_write]; | ||
| 1239 | bb_pool = ctx->mem.ccs_bb_pool; | ||
| 1240 | |||
| 1241 | guard(mutex) (xe_sa_bo_swap_guard(bb_pool)); | ||
| 1242 | xe_sa_bo_swap_shadow(bb_pool); | ||
| 1243 | |||
| 1244 | cs = xe_sa_bo_cpu_addr(bb->bo); | ||
| 1245 | memset(cs, MI_NOOP, bb->len * sizeof(u32)); | ||
| 1246 | xe_sriov_vf_ccs_rw_update_bb_addr(ctx); | ||
| 1247 | |||
| 1248 | xe_sa_bo_sync_shadow(bb->bo); | ||
| 1249 | |||
| 1250 | xe_bb_free(bb, NULL); | ||
| 1251 | src_bo->bb_ccs[read_write] = NULL; | ||
| 1201 | } | 1252 | } |
| 1202 | 1253 | ||
| 1203 | /** | 1254 | /** |
| @@ -134,6 +134,9 @@ int xe_migrate_ccs_rw_copy(struct xe_tile *tile, struct xe_exec_queue *q, · 133 unmodified lines | |||
| 134 | struct xe_bo *src_bo, | 134 | struct xe_bo *src_bo, |
| 135 | enum xe_sriov_vf_ccs_rw_ctxs read_write); | 135 | enum xe_sriov_vf_ccs_rw_ctxs read_write); |
| 136 | 136 | ||
| 137 | void xe_migrate_ccs_rw_copy_clear(struct xe_bo *src_bo, | ||
| 138 | enum xe_sriov_vf_ccs_rw_ctxs read_write); | ||
| 139 | |||
| 137 | struct xe_lrc *xe_migrate_lrc(struct xe_migrate *migrate); | 140 | struct xe_lrc *xe_migrate_lrc(struct xe_migrate *migrate); |
| 138 | struct xe_exec_queue *xe_migrate_exec_queue(struct xe_migrate *migrate); | 141 | struct xe_exec_queue *xe_migrate_exec_queue(struct xe_migrate *migrate); |
| 139 | struct dma_fence *xe_migrate_vram_copy_chunk(struct xe_bo *vram_bo, u64 vram_offset, | 142 | struct dma_fence *xe_migrate_vram_copy_chunk(struct xe_bo *vram_bo, u64 vram_offset, |
| @@ -811,26 +811,20 @@ int xe_mocs_dump(struct xe_gt *gt, struct drm_printer *p) · 810 unmodified lines | |||
| 811 | struct xe_device *xe = gt_to_xe(gt); | 811 | struct xe_device *xe = gt_to_xe(gt); |
| 812 | enum xe_force_wake_domains domain; | 812 | enum xe_force_wake_domains domain; |
| 813 | struct xe_mocs_info table; | 813 | struct xe_mocs_info table; |
| 814 | unsigned int fw_ref, flags; | 814 | unsigned int flags; |
| 815 | int err = 0; | ||
| 816 | 815 | ||
| 817 | flags = get_mocs_settings(xe, &table); | 816 | flags = get_mocs_settings(xe, &table); |
| 818 | 817 | ||
| 819 | domain = flags & HAS_LNCF_MOCS ? XE_FORCEWAKE_ALL : XE_FW_GT; | 818 | domain = flags & HAS_LNCF_MOCS ? XE_FORCEWAKE_ALL : XE_FW_GT; |
| 820 | xe_pm_runtime_get_noresume(xe); | ||
| 821 | fw_ref = xe_force_wake_get(gt_to_fw(gt), domain); | ||
| 822 | 819 | ||
| 823 | if (!xe_force_wake_ref_has_domain(fw_ref, domain)) { | 820 | guard(xe_pm_runtime_noresume)(xe); |
| 824 | err = -ETIMEDOUT; | 821 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), domain); |
| 825 | goto err_fw; | 822 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, domain)) |
| 826 | } | 823 | return -ETIMEDOUT; |
| 827 | 824 | ||
| 828 | table.ops->dump(&table, flags, gt, p); | 825 | table.ops->dump(&table, flags, gt, p); |
| 829 | 826 | ||
| 830 | err_fw: | 827 | return 0; |
| 831 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 832 | xe_pm_runtime_put(xe); | ||
| 833 | return err; | ||
| 834 | } | 828 | } |
| 835 | 829 | ||
| 836 | #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) | 830 | #if IS_ENABLED(CONFIG_DRM_XE_KUNIT_TEST) |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | |||
| 10 | #include "xe_device_types.h" | 10 | #include "xe_device_types.h" |
| 11 | #include "xe_mmio.h" | 11 | #include "xe_mmio.h" |
| 12 | #include "xe_nvm.h" | 12 | #include "xe_nvm.h" |
| 13 | #include "xe_pcode_api.h" | ||
| 13 | #include "regs/xe_gsc_regs.h" | 14 | #include "regs/xe_gsc_regs.h" |
| 14 | #include "xe_sriov.h" | 15 | #include "xe_sriov.h" |
| 15 | 16 | ||
| @@ -45,39 +46,50 @@ static bool xe_nvm_non_posted_erase(struct xe_device *xe) · 29 unmodified lines | |||
| 45 | { | 46 | { |
| 46 | struct xe_mmio *mmio = xe_root_tile_mmio(xe); | 47 | struct xe_mmio *mmio = xe_root_tile_mmio(xe); |
| 47 | 48 | ||
| 48 | if (xe->info.platform != XE_BATTLEMAGE) | 49 | switch (xe->info.platform) { |
| 50 | case XE_CRESCENTISLAND: | ||
| 51 | case XE_BATTLEMAGE: | ||
| 52 | return !(xe_mmio_read32(mmio, XE_REG(GEN12_CNTL_PROTECTED_NVM_REG)) & | ||
| 53 | NVM_NON_POSTED_ERASE_CHICKEN_BIT); | ||
| 54 | default: | ||
| 49 | return false; | 55 | return false; |
| 50 | return !(xe_mmio_read32(mmio, XE_REG(GEN12_CNTL_PROTECTED_NVM_REG)) & | 56 | } |
| 51 | NVM_NON_POSTED_ERASE_CHICKEN_BIT); | ||
| 52 | } | 57 | } |
| 53 | 58 | ||
| 54 | static bool xe_nvm_writable_override(struct xe_device *xe) | 59 | static bool xe_nvm_writable_override(struct xe_device *xe) |
| 55 | { | 60 | { |
| 56 | struct xe_mmio *mmio = xe_root_tile_mmio(xe); | 61 | struct xe_mmio *mmio = xe_root_tile_mmio(xe); |
| 57 | bool writable_override; | 62 | bool writable_override; |
| 58 | resource_size_t base; | 63 | struct xe_reg reg; |
| 64 | u32 test_bit; | ||
| 59 | 65 | ||
| 60 | switch (xe->info.platform) { | 66 | switch (xe->info.platform) { |
| 67 | case XE_CRESCENTISLAND: | ||
| 68 | reg = PCODE_SCRATCH(0); | ||
| 69 | test_bit = FDO_MODE; | ||
| 70 | break; | ||
| 61 | case XE_BATTLEMAGE: | 71 | case XE_BATTLEMAGE: |
| 62 | base = DG2_GSC_HECI2_BASE; | 72 | reg = HECI_FWSTS2(DG2_GSC_HECI2_BASE); |
| 73 | test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE; | ||
| 63 | break; | 74 | break; |
| 64 | case XE_PVC: | 75 | case XE_PVC: |
| 65 | base = PVC_GSC_HECI2_BASE; | 76 | reg = HECI_FWSTS2(PVC_GSC_HECI2_BASE); |
| 77 | test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE; | ||
| 66 | break; | 78 | break; |
| 67 | case XE_DG2: | 79 | case XE_DG2: |
| 68 | base = DG2_GSC_HECI2_BASE; | 80 | reg = HECI_FWSTS2(DG2_GSC_HECI2_BASE); |
| 81 | test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE; | ||
| 69 | break; | 82 | break; |
| 70 | case XE_DG1: | 83 | case XE_DG1: |
| 71 | base = DG1_GSC_HECI2_BASE; | 84 | reg = HECI_FWSTS2(DG1_GSC_HECI2_BASE); |
| 85 | test_bit = HECI_FW_STATUS_2_NVM_ACCESS_MODE; | ||
| 72 | break; | 86 | break; |
| 73 | default: | 87 | default: |
| 74 | drm_err(&xe->drm, "Unknown platform\n"); | 88 | drm_err(&xe->drm, "Unknown platform\n"); |
| 75 | return true; | 89 | return true; |
| 76 | } | 90 | } |
| 77 | 91 | ||
| 78 | writable_override = | 92 | writable_override = !(xe_mmio_read32(mmio, reg) & test_bit); |
| 79 | !(xe_mmio_read32(mmio, HECI_FWSTS2(base)) & | ||
| 80 | HECI_FW_STATUS_2_NVM_ACCESS_MODE); | ||
| 81 | if (writable_override) | 93 | if (writable_override) |
| 82 | drm_info(&xe->drm, "NVM access overridden by jumper\n"); | 94 | drm_info(&xe->drm, "NVM access overridden by jumper\n"); |
| 83 | return writable_override; | 95 | return writable_override; |
| @@ -1941,6 +1941,7 @@ static bool oa_unit_supports_oa_format(struct xe_oa_open_param *param, int type) · 1940 unmodified lines | |||
| 1941 | type == DRM_XE_OA_FMT_TYPE_OAC || type == DRM_XE_OA_FMT_TYPE_PEC; | 1941 | type == DRM_XE_OA_FMT_TYPE_OAC || type == DRM_XE_OA_FMT_TYPE_PEC; |
| 1942 | case DRM_XE_OA_UNIT_TYPE_OAM: | 1942 | case DRM_XE_OA_UNIT_TYPE_OAM: |
| 1943 | case DRM_XE_OA_UNIT_TYPE_OAM_SAG: | 1943 | case DRM_XE_OA_UNIT_TYPE_OAM_SAG: |
| 1944 | case DRM_XE_OA_UNIT_TYPE_MERT: | ||
| 1944 | return type == DRM_XE_OA_FMT_TYPE_OAM || type == DRM_XE_OA_FMT_TYPE_OAM_MPEC; | 1945 | return type == DRM_XE_OA_FMT_TYPE_OAM || type == DRM_XE_OA_FMT_TYPE_OAM_MPEC; |
| 1945 | default: | 1946 | default: |
| 1946 | return false; | 1947 | return false; |
| @@ -1966,10 +1967,6 @@ static int xe_oa_assign_hwe(struct xe_oa *oa, struct xe_oa_open_param *param) · 19 unmodified lines | |||
| 1966 | enum xe_hw_engine_id id; | 1967 | enum xe_hw_engine_id id; |
| 1967 | int ret = 0; | 1968 | int ret = 0; |
| 1968 | 1969 | ||
| 1969 | /* If not provided, OA unit defaults to OA unit 0 as per uapi */ | ||
| 1970 | if (!param->oa_unit) | ||
| 1971 | param->oa_unit = &xe_root_mmio_gt(oa->xe)->oa.oa_unit[0]; | ||
| 1972 | |||
| 1973 | /* When we have an exec_q, get hwe from the exec_q */ | 1970 | /* When we have an exec_q, get hwe from the exec_q */ |
| 1974 | if (param->exec_q) { | 1971 | if (param->exec_q) { |
| 1975 | param->hwe = xe_gt_hw_engine(param->exec_q->gt, param->exec_q->class, | 1972 | param->hwe = xe_gt_hw_engine(param->exec_q->gt, param->exec_q->class, |
| @@ -2035,7 +2032,15 @@ int xe_oa_stream_open_ioctl(struct drm_device *dev, u64 data, struct drm_file *f · 59 unmodified lines | |||
| 2035 | if (ret) | 2032 | if (ret) |
| 2036 | return ret; | 2033 | return ret; |
| 2037 | 2034 | ||
| 2035 | /* If not provided, OA unit defaults to OA unit 0 as per uapi */ | ||
| 2036 | if (!param.oa_unit) | ||
| 2037 | param.oa_unit = &xe_root_mmio_gt(oa->xe)->oa.oa_unit[0]; | ||
| 2038 | |||
| 2038 | if (param.exec_queue_id > 0) { | 2039 | if (param.exec_queue_id > 0) { |
| 2040 | /* An exec_queue is only needed for OAR/OAC functionality on OAG */ | ||
| 2041 | if (XE_IOCTL_DBG(oa->xe, param.oa_unit->type != DRM_XE_OA_UNIT_TYPE_OAG)) | ||
| 2042 | return -EINVAL; | ||
| 2043 | |||
| 2039 | param.exec_q = xe_exec_queue_lookup(xef, param.exec_queue_id); | 2044 | param.exec_q = xe_exec_queue_lookup(xef, param.exec_queue_id); |
| 2040 | if (XE_IOCTL_DBG(oa->xe, !param.exec_q)) | 2045 | if (XE_IOCTL_DBG(oa->xe, !param.exec_q)) |
| 2041 | return -ENOENT; | 2046 | return -ENOENT; |
| @@ -2224,6 +2229,8 @@ static const struct xe_mmio_range xe2_oa_mux_regs[] = { · 182 unmodified lines | |||
| 2224 | { .start = 0xE18C, .end = 0xE18C }, /* SAMPLER_MODE */ | 2229 | { .start = 0xE18C, .end = 0xE18C }, /* SAMPLER_MODE */ |
| 2225 | { .start = 0xE590, .end = 0xE590 }, /* TDL_LSC_LAT_MEASURE_TDL_GFX */ | 2230 | { .start = 0xE590, .end = 0xE590 }, /* TDL_LSC_LAT_MEASURE_TDL_GFX */ |
| 2226 | { .start = 0x13000, .end = 0x137FC }, /* PES_0_PESL0 - PES_63_UPPER_PESL3 */ | 2231 | { .start = 0x13000, .end = 0x137FC }, /* PES_0_PESL0 - PES_63_UPPER_PESL3 */ |
| 2232 | { .start = 0x145194, .end = 0x145194 }, /* SYS_MEM_LAT_MEASURE */ | ||
| 2233 | { .start = 0x145340, .end = 0x14537C }, /* MERTSS_PES_0 - MERTSS_PES_7 */ | ||
| 2227 | {}, | 2234 | {}, |
| 2228 | }; | 2235 | }; |
| 2229 | 2236 | ||
| @@ -2515,7 +2522,12 @@ int xe_oa_register(struct xe_device *xe) · 285 unmodified lines | |||
| 2515 | static u32 num_oa_units_per_gt(struct xe_gt *gt) | 2522 | static u32 num_oa_units_per_gt(struct xe_gt *gt) |
| 2516 | { | 2523 | { |
| 2517 | if (xe_gt_is_main_type(gt) || GRAPHICS_VER(gt_to_xe(gt)) < 20) | 2524 | if (xe_gt_is_main_type(gt) || GRAPHICS_VER(gt_to_xe(gt)) < 20) |
| 2518 | return 1; | 2525 | /* |
| 2526 | * Mert OA unit belongs to the SoC, not a gt, so should be accessed using | ||
| 2527 | * xe_root_tile_mmio(). However, for all known platforms this is the same as | ||
| 2528 | * accessing via xe_root_mmio_gt()->mmio. | ||
| 2529 | */ | ||
| 2530 | return xe_device_has_mert(gt_to_xe(gt)) ? 2 : 1; | ||
| 2519 | else if (!IS_DGFX(gt_to_xe(gt))) | 2531 | else if (!IS_DGFX(gt_to_xe(gt))) |
| 2520 | return XE_OAM_UNIT_SCMI_0 + 1; /* SAG + SCMI_0 */ | 2532 | return XE_OAM_UNIT_SCMI_0 + 1; /* SAG + SCMI_0 */ |
| 2521 | else | 2533 | else |
| @@ -2570,40 +2582,57 @@ static u32 __hwe_oa_unit(struct xe_hw_engine *hwe) · 48 unmodified lines | |||
| 2570 | static struct xe_oa_regs __oam_regs(u32 base) | 2582 | static struct xe_oa_regs __oam_regs(u32 base) |
| 2571 | { | 2583 | { |
| 2572 | return (struct xe_oa_regs) { | 2584 | return (struct xe_oa_regs) { |
| 2573 | base, | 2585 | .base = base, |
| 2574 | OAM_HEAD_POINTER(base), | 2586 | .oa_head_ptr = OAM_HEAD_POINTER(base), |
| 2575 | OAM_TAIL_POINTER(base), | 2587 | .oa_tail_ptr = OAM_TAIL_POINTER(base), |
| 2576 | OAM_BUFFER(base), | 2588 | .oa_buffer = OAM_BUFFER(base), |
| 2577 | OAM_CONTEXT_CONTROL(base), | 2589 | .oa_ctx_ctrl = OAM_CONTEXT_CONTROL(base), |
| 2578 | OAM_CONTROL(base), | 2590 | .oa_ctrl = OAM_CONTROL(base), |
| 2579 | OAM_DEBUG(base), | 2591 | .oa_debug = OAM_DEBUG(base), |
| 2580 | OAM_STATUS(base), | 2592 | .oa_status = OAM_STATUS(base), |
| 2581 | OAM_CONTROL_COUNTER_SEL_MASK, | 2593 | .oa_mmio_trg = OAM_MMIO_TRG(base), |
| 2594 | .oa_ctrl_counter_select_mask = OAM_CONTROL_COUNTER_SEL_MASK, | ||
| 2582 | }; | 2595 | }; |
| 2583 | } | 2596 | } |
| 2584 | 2597 | ||
| 2585 | static struct xe_oa_regs __oag_regs(void) | 2598 | static struct xe_oa_regs __oag_regs(void) |
| 2586 | { | 2599 | { |
| 2587 | return (struct xe_oa_regs) { | 2600 | return (struct xe_oa_regs) { |
| 2588 | 0, | 2601 | .base = 0, |
| 2589 | OAG_OAHEADPTR, | 2602 | .oa_head_ptr = OAG_OAHEADPTR, |
| 2590 | OAG_OATAILPTR, | 2603 | .oa_tail_ptr = OAG_OATAILPTR, |
| 2591 | OAG_OABUFFER, | 2604 | .oa_buffer = OAG_OABUFFER, |
| 2592 | OAG_OAGLBCTXCTRL, | 2605 | .oa_ctx_ctrl = OAG_OAGLBCTXCTRL, |
| 2593 | OAG_OACONTROL, | 2606 | .oa_ctrl = OAG_OACONTROL, |
| 2594 | OAG_OA_DEBUG, | 2607 | .oa_debug = OAG_OA_DEBUG, |
| 2595 | OAG_OASTATUS, | 2608 | .oa_status = OAG_OASTATUS, |
| 2596 | OAG_OACONTROL_OA_COUNTER_SEL_MASK, | 2609 | .oa_mmio_trg = OAG_MMIOTRIGGER, |
| 2610 | .oa_ctrl_counter_select_mask = OAG_OACONTROL_OA_COUNTER_SEL_MASK, | ||
| 2611 | }; | ||
| 2612 | } | ||
| 2613 | |||
| 2614 | static struct xe_oa_regs __oamert_regs(void) | ||
| 2615 | { | ||
| 2616 | return (struct xe_oa_regs) { | ||
| 2617 | .base = 0, | ||
| 2618 | .oa_head_ptr = OAMERT_HEAD_POINTER, | ||
| 2619 | .oa_tail_ptr = OAMERT_TAIL_POINTER, | ||
| 2620 | .oa_buffer = OAMERT_BUFFER, | ||
| 2621 | .oa_ctx_ctrl = OAMERT_CONTEXT_CONTROL, | ||
| 2622 | .oa_ctrl = OAMERT_CONTROL, | ||
| 2623 | .oa_debug = OAMERT_DEBUG, | ||
| 2624 | .oa_status = OAMERT_STATUS, | ||
| 2625 | .oa_mmio_trg = OAMERT_MMIO_TRG, | ||
| 2626 | .oa_ctrl_counter_select_mask = OAM_CONTROL_COUNTER_SEL_MASK, | ||
| 2597 | }; | 2627 | }; |
| 2598 | } | 2628 | } |
| 2599 | 2629 | ||
| 2600 | static void __xe_oa_init_oa_units(struct xe_gt *gt) | 2630 | static void __xe_oa_init_oa_units(struct xe_gt *gt) |
| 2601 | { | 2631 | { |
| 2602 | /* Actual address is MEDIA_GT_GSI_OFFSET + oam_base_addr[i] */ | ||
| 2603 | const u32 oam_base_addr[] = { | 2632 | const u32 oam_base_addr[] = { |
| 2604 | [XE_OAM_UNIT_SAG] = 0x13000, | 2633 | [XE_OAM_UNIT_SAG] = XE_OAM_SAG_BASE, |
| 2605 | [XE_OAM_UNIT_SCMI_0] = 0x14000, | 2634 | [XE_OAM_UNIT_SCMI_0] = XE_OAM_SCMI_0_BASE, |
| 2606 | [XE_OAM_UNIT_SCMI_1] = 0x14800, | 2635 | [XE_OAM_UNIT_SCMI_1] = XE_OAM_SCMI_1_BASE, |
| 2607 | }; | 2636 | }; |
| 2608 | int i, num_units = gt->oa.num_oa_units; | 2637 | int i, num_units = gt->oa.num_oa_units; |
| 2609 | 2638 | ||
| @@ -2611,8 +2640,15 @@ static void __xe_oa_init_oa_units(struct xe_gt *gt) · 1 unmodified line | |||
| 2611 | struct xe_oa_unit *u = >->oa.oa_unit[i]; | 2640 | struct xe_oa_unit *u = >->oa.oa_unit[i]; |
| 2612 | 2641 | ||
| 2613 | if (xe_gt_is_main_type(gt)) { | 2642 | if (xe_gt_is_main_type(gt)) { |
| 2614 | u->regs = __oag_regs(); | 2643 | if (!i) { |
| 2615 | u->type = DRM_XE_OA_UNIT_TYPE_OAG; | 2644 | u->regs = __oag_regs(); |
| 2645 | u->type = DRM_XE_OA_UNIT_TYPE_OAG; | ||
| 2646 | } else { | ||
| 2647 | xe_gt_assert(gt, xe_device_has_mert(gt_to_xe(gt))); | ||
| 2648 | xe_gt_assert(gt, gt == xe_root_mmio_gt(gt_to_xe(gt))); | ||
| 2649 | u->regs = __oamert_regs(); | ||
| 2650 | u->type = DRM_XE_OA_UNIT_TYPE_MERT; | ||
| 2651 | } | ||
| 2616 | } else { | 2652 | } else { |
| 2617 | xe_gt_assert(gt, GRAPHICS_VERx100(gt_to_xe(gt)) >= 1270); | 2653 | xe_gt_assert(gt, GRAPHICS_VERx100(gt_to_xe(gt)) >= 1270); |
| 2618 | u->regs = __oam_regs(oam_base_addr[i]); | 2654 | u->regs = __oam_regs(oam_base_addr[i]); |
| @@ -87,6 +87,7 @@ struct xe_oa_regs { · 86 unmodified lines | |||
| 87 | struct xe_reg oa_ctrl; | 87 | struct xe_reg oa_ctrl; |
| 88 | struct xe_reg oa_debug; | 88 | struct xe_reg oa_debug; |
| 89 | struct xe_reg oa_status; | 89 | struct xe_reg oa_status; |
| 90 | struct xe_reg oa_mmio_trg; | ||
| 90 | u32 oa_ctrl_counter_select_mask; | 91 | u32 oa_ctrl_counter_select_mask; |
| 91 | }; | 92 | }; |
| 92 | 93 | ||
| @@ -0,0 +1,136 @@ | |||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | /* | ||
| 3 | * Copyright © 2025 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #include <linux/bitfield.h> | ||
| 7 | #include <linux/kref.h> | ||
| 8 | #include <linux/mm.h> | ||
| 9 | #include <linux/slab.h> | ||
| 10 | |||
| 11 | #include "xe_page_reclaim.h" | ||
| 12 | |||
| 13 | #include "regs/xe_gt_regs.h" | ||
| 14 | #include "xe_assert.h" | ||
| 15 | #include "xe_macros.h" | ||
| 16 | #include "xe_mmio.h" | ||
| 17 | #include "xe_pat.h" | ||
| 18 | #include "xe_sa.h" | ||
| 19 | #include "xe_tlb_inval_types.h" | ||
| 20 | #include "xe_vm.h" | ||
| 21 | |||
| 22 | /** | ||
| 23 | * xe_page_reclaim_skip() - Decide whether PRL should be skipped for a VMA | ||
| 24 | * @tile: Tile owning the VMA | ||
| 25 | * @vma: VMA under consideration | ||
| 26 | * | ||
| 27 | * PPC flushing may be handled by HW for specific PAT encodings. | ||
| 28 | * Skip PPC flushing/Page Reclaim for scenarios below due to redundant | ||
| 29 | * flushes. | ||
| 30 | * - pat_index is transient display (1) | ||
| 31 | * | ||
| 32 | * Return: true when page reclamation is unnecessary, false otherwise. | ||
| 33 | */ | ||
| 34 | bool xe_page_reclaim_skip(struct xe_tile *tile, struct xe_vma *vma) | ||
| 35 | { | ||
| 36 | u8 l3_policy; | ||
| 37 | |||
| 38 | l3_policy = xe_pat_index_get_l3_policy(tile->xe, vma->attr.pat_index); | ||
| 39 | |||
| 40 | /* | ||
| 41 | * - l3_policy: 0=WB, 1=XD ("WB - Transient Display"), 3=UC | ||
| 42 | * Transient display flushes is taken care by HW, l3_policy = 1. | ||
| 43 | * | ||
| 44 | * HW will sequence these transient flushes at various sync points so | ||
| 45 | * any event of page reclamation will hit these sync points before | ||
| 46 | * page reclamation could execute. | ||
| 47 | */ | ||
| 48 | return (l3_policy == XE_L3_POLICY_XD); | ||
| 49 | } | ||
| 50 | |||
| 51 | /** | ||
| 52 | * xe_page_reclaim_create_prl_bo() - Back a PRL with a suballocated GGTT BO | ||
| 53 | * @tlb_inval: TLB invalidation frontend associated with the request | ||
| 54 | * @prl: page reclaim list data that bo will copy from | ||
| 55 | * @fence: tlb invalidation fence that page reclaim action is paired to | ||
| 56 | * | ||
| 57 | * Suballocates a 4K BO out of the tile reclaim pool, copies the PRL CPU | ||
| 58 | * copy into the BO and queues the buffer for release when @fence signals. | ||
| 59 | * | ||
| 60 | * Return: struct drm_suballoc pointer on success or ERR_PTR on failure. | ||
| 61 | */ | ||
| 62 | struct drm_suballoc *xe_page_reclaim_create_prl_bo(struct xe_tlb_inval *tlb_inval, | ||
| 63 | struct xe_page_reclaim_list *prl, | ||
| 64 | struct xe_tlb_inval_fence *fence) | ||
| 65 | { | ||
| 66 | struct xe_gt *gt = container_of(tlb_inval, struct xe_gt, tlb_inval); | ||
| 67 | struct xe_tile *tile = gt_to_tile(gt); | ||
| 68 | /* (+1) for NULL page_reclaim_entry to indicate end of list */ | ||
| 69 | int prl_size = min(prl->num_entries + 1, XE_PAGE_RECLAIM_MAX_ENTRIES) * | ||
| 70 | sizeof(struct xe_guc_page_reclaim_entry); | ||
| 71 | struct drm_suballoc *prl_sa; | ||
| 72 | |||
| 73 | /* Maximum size of PRL is 1 4K-page */ | ||
| 74 | prl_sa = __xe_sa_bo_new(tile->mem.reclaim_pool, | ||
| 75 | prl_size, GFP_ATOMIC); | ||
| 76 | if (IS_ERR(prl_sa)) | ||
| 77 | return prl_sa; | ||
| 78 | |||
| 79 | memcpy(xe_sa_bo_cpu_addr(prl_sa), prl->entries, | ||
| 80 | prl_size); | ||
| 81 | xe_sa_bo_flush_write(prl_sa); | ||
| 82 | /* Queue up sa_bo_free on tlb invalidation fence signal */ | ||
| 83 | xe_sa_bo_free(prl_sa, &fence->base); | ||
| 84 | |||
| 85 | return prl_sa; | ||
| 86 | } | ||
| 87 | |||
| 88 | /** | ||
| 89 | * xe_page_reclaim_list_invalidate() - Mark a PRL as invalid | ||
| 90 | * @prl: Page reclaim list to reset | ||
| 91 | * | ||
| 92 | * Clears the entries pointer and marks the list as invalid so | ||
| 93 | * future use knows PRL is unusable. It is expected that the entries | ||
| 94 | * have already been released. | ||
| 95 | */ | ||
| 96 | void xe_page_reclaim_list_invalidate(struct xe_page_reclaim_list *prl) | ||
| 97 | { | ||
| 98 | xe_page_reclaim_entries_put(prl->entries); | ||
| 99 | prl->entries = NULL; | ||
| 100 | prl->num_entries = XE_PAGE_RECLAIM_INVALID_LIST; | ||
| 101 | } | ||
| 102 | |||
| 103 | /** | ||
| 104 | * xe_page_reclaim_list_init() - Initialize a page reclaim list | ||
| 105 | * @prl: Page reclaim list to initialize | ||
| 106 | * | ||
| 107 | * NULLs both values in list to prepare on initalization. | ||
| 108 | */ | ||
| 109 | void xe_page_reclaim_list_init(struct xe_page_reclaim_list *prl) | ||
| 110 | { | ||
| 111 | // xe_page_reclaim_list_invalidate(prl); | ||
| 112 | prl->entries = NULL; | ||
| 113 | prl->num_entries = 0; | ||
| 114 | } | ||
| 115 | |||
| 116 | /** | ||
| 117 | * xe_page_reclaim_list_alloc_entries() - Allocate page reclaim list entries | ||
| 118 | * @prl: Page reclaim list to allocate entries for | ||
| 119 | * | ||
| 120 | * Allocate one 4K page for the PRL entries, otherwise assign prl->entries to NULL. | ||
| 121 | */ | ||
| 122 | int xe_page_reclaim_list_alloc_entries(struct xe_page_reclaim_list *prl) | ||
| 123 | { | ||
| 124 | struct page *page; | ||
| 125 | |||
| 126 | if (XE_WARN_ON(prl->entries)) | ||
| 127 | return 0; | ||
| 128 | |||
| 129 | page = alloc_page(GFP_KERNEL | __GFP_ZERO); | ||
| 130 | if (page) { | ||
| 131 | prl->entries = page_address(page); | ||
| 132 | prl->num_entries = 0; | ||
| 133 | } | ||
| 134 | |||
| 135 | return page ? 0 : -ENOMEM; | ||
| 136 | } | ||
| @@ -0,0 +1,105 @@ | |||
| 1 | /* SPDX-License-Identifier: MIT */ | ||
| 2 | /* | ||
| 3 | * Copyright © 2025 Intel Corporation | ||
| 4 | */ | ||
| 5 | |||
| 6 | #ifndef _XE_PAGE_RECLAIM_H_ | ||
| 7 | #define _XE_PAGE_RECLAIM_H_ | ||
| 8 | |||
| 9 | #include <linux/kref.h> | ||
| 10 | #include <linux/mm.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/types.h> | ||
| 13 | #include <linux/workqueue.h> | ||
| 14 | #include <linux/bits.h> | ||
| 15 | |||
| 16 | #define XE_PAGE_RECLAIM_MAX_ENTRIES 512 | ||
| 17 | #define XE_PAGE_RECLAIM_LIST_MAX_SIZE SZ_4K | ||
| 18 | |||
| 19 | struct xe_tlb_inval; | ||
| 20 | struct xe_tlb_inval_fence; | ||
| 21 | struct xe_tile; | ||
| 22 | struct xe_vma; | ||
| 23 | |||
| 24 | struct xe_guc_page_reclaim_entry { | ||
| 25 | u64 qw; | ||
| 26 | /* valid reclaim entry bit */ | ||
| 27 | #define XE_PAGE_RECLAIM_VALID BIT_ULL(0) | ||
| 28 | /* | ||
| 29 | * offset order of page size to be reclaimed | ||
| 30 | * page_size = 1 << (XE_PTE_SHIFT + reclamation_size) | ||
| 31 | */ | ||
| 32 | #define XE_PAGE_RECLAIM_SIZE GENMASK_ULL(6, 1) | ||
| 33 | #define XE_PAGE_RECLAIM_RSVD_0 GENMASK_ULL(11, 7) | ||
| 34 | /* lower 20 bits of the physical address */ | ||
| 35 | #define XE_PAGE_RECLAIM_ADDR_LO GENMASK_ULL(31, 12) | ||
| 36 | /* upper 20 bits of the physical address */ | ||
| 37 | #define XE_PAGE_RECLAIM_ADDR_HI GENMASK_ULL(51, 32) | ||
| 38 | #define XE_PAGE_RECLAIM_RSVD_1 GENMASK_ULL(63, 52) | ||
| 39 | } __packed; | ||
| 40 | |||
| 41 | struct xe_page_reclaim_list { | ||
| 42 | /** @entries: array of page reclaim entries, page allocated */ | ||
| 43 | struct xe_guc_page_reclaim_entry *entries; | ||
| 44 | /** @num_entries: number of entries */ | ||
| 45 | int num_entries; | ||
| 46 | #define XE_PAGE_RECLAIM_INVALID_LIST -1 | ||
| 47 | }; | ||
| 48 | |||
| 49 | /** | ||
| 50 | * xe_page_reclaim_list_is_new() - Check if PRL is new allocation | ||
| 51 | * @prl: Pointer to page reclaim list | ||
| 52 | * | ||
| 53 | * PRL indicates it hasn't been allocated through both values being NULL | ||
| 54 | */ | ||
| 55 | static inline bool xe_page_reclaim_list_is_new(struct xe_page_reclaim_list *prl) | ||
| 56 | { | ||
| 57 | return !prl->entries && prl->num_entries == 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | /** | ||
| 61 | * xe_page_reclaim_list_valid() - Check if the page reclaim list is valid | ||
| 62 | * @prl: Pointer to page reclaim list | ||
| 63 | * | ||
| 64 | * PRL uses the XE_PAGE_RECLAIM_INVALID_LIST to indicate that a PRL | ||
| 65 | * is unusable. | ||
| 66 | */ | ||
| 67 | static inline bool xe_page_reclaim_list_valid(struct xe_page_reclaim_list *prl) | ||
| 68 | { | ||
| 69 | return !xe_page_reclaim_list_is_new(prl) && | ||
| 70 | prl->num_entries != XE_PAGE_RECLAIM_INVALID_LIST; | ||
| 71 | } | ||
| 72 | |||
| 73 | bool xe_page_reclaim_skip(struct xe_tile *tile, struct xe_vma *vma); | ||
| 74 | struct drm_suballoc *xe_page_reclaim_create_prl_bo(struct xe_tlb_inval *tlb_inval, | ||
| 75 | struct xe_page_reclaim_list *prl, | ||
| 76 | struct xe_tlb_inval_fence *fence); | ||
| 77 | void xe_page_reclaim_list_invalidate(struct xe_page_reclaim_list *prl); | ||
| 78 | void xe_page_reclaim_list_init(struct xe_page_reclaim_list *prl); | ||
| 79 | int xe_page_reclaim_list_alloc_entries(struct xe_page_reclaim_list *prl); | ||
| 80 | /** | ||
| 81 | * xe_page_reclaim_entries_get() - Increment the reference count of page reclaim entries. | ||
| 82 | * @entries: Pointer to the array of page reclaim entries. | ||
| 83 | * | ||
| 84 | * This function increments the reference count of the backing page. | ||
| 85 | */ | ||
| 86 | static inline void xe_page_reclaim_entries_get(struct xe_guc_page_reclaim_entry *entries) | ||
| 87 | { | ||
| 88 | if (entries) | ||
| 89 | get_page(virt_to_page(entries)); | ||
| 90 | } | ||
| 91 | |||
| 92 | /** | ||
| 93 | * xe_page_reclaim_entries_put() - Decrement the reference count of page reclaim entries. | ||
| 94 | * @entries: Pointer to the array of page reclaim entries. | ||
| 95 | * | ||
| 96 | * This function decrements the reference count of the backing page | ||
| 97 | * and frees it if the count reaches zero. | ||
| 98 | */ | ||
| 99 | static inline void xe_page_reclaim_entries_put(struct xe_guc_page_reclaim_entry *entries) | ||
| 100 | { | ||
| 101 | if (entries) | ||
| 102 | put_page(virt_to_page(entries)); | ||
| 103 | } | ||
| 104 | |||
| 105 | #endif /* _XE_PAGE_RECLAIM_H_ */ | ||
| @@ -223,22 +223,22 @@ static bool xe_pagefault_queue_pop(struct xe_pagefault_queue *pf_queue, · 222 unmodified lines | |||
| 223 | 223 | ||
| 224 | static void xe_pagefault_print(struct xe_pagefault *pf) | 224 | static void xe_pagefault_print(struct xe_pagefault *pf) |
| 225 | { | 225 | { |
| 226 | xe_gt_dbg(pf->gt, "\n\tASID: %d\n" | 226 | xe_gt_info(pf->gt, "\n\tASID: %d\n" |
| 227 | "\tFaulted Address: 0x%08x%08x\n" | 227 | "\tFaulted Address: 0x%08x%08x\n" |
| 228 | "\tFaultType: %d\n" | 228 | "\tFaultType: %d\n" |
| 229 | "\tAccessType: %d\n" | 229 | "\tAccessType: %d\n" |
| 230 | "\tFaultLevel: %d\n" | 230 | "\tFaultLevel: %d\n" |
| 231 | "\tEngineClass: %d %s\n" | 231 | "\tEngineClass: %d %s\n" |
| 232 | "\tEngineInstance: %d\n", | 232 | "\tEngineInstance: %d\n", |
| 233 | pf->consumer.asid, | 233 | pf->consumer.asid, |
| 234 | upper_32_bits(pf->consumer.page_addr), | 234 | upper_32_bits(pf->consumer.page_addr), |
| 235 | lower_32_bits(pf->consumer.page_addr), | 235 | lower_32_bits(pf->consumer.page_addr), |
| 236 | pf->consumer.fault_type, | 236 | pf->consumer.fault_type, |
| 237 | pf->consumer.access_type, | 237 | pf->consumer.access_type, |
| 238 | pf->consumer.fault_level, | 238 | pf->consumer.fault_level, |
| 239 | pf->consumer.engine_class, | 239 | pf->consumer.engine_class, |
| 240 | xe_hw_engine_class_to_str(pf->consumer.engine_class), | 240 | xe_hw_engine_class_to_str(pf->consumer.engine_class), |
| 241 | pf->consumer.engine_instance); | 241 | pf->consumer.engine_instance); |
| 242 | } | 242 | } |
| 243 | 243 | ||
| 244 | static void xe_pagefault_queue_work(struct work_struct *w) | 244 | static void xe_pagefault_queue_work(struct work_struct *w) |
| @@ -260,8 +260,8 @@ static void xe_pagefault_queue_work(struct work_struct *w) · 15 unmodified lines | |||
| 260 | err = xe_pagefault_service(&pf); | 260 | err = xe_pagefault_service(&pf); |
| 261 | if (err) { | 261 | if (err) { |
| 262 | xe_pagefault_print(&pf); | 262 | xe_pagefault_print(&pf); |
| 263 | xe_gt_dbg(pf.gt, "Fault response: Unsuccessful %pe\n", | 263 | xe_gt_info(pf.gt, "Fault response: Unsuccessful %pe\n", |
| 264 | ERR_PTR(err)); | 264 | ERR_PTR(err)); |
| 265 | } | 265 | } |
| 266 | 266 | ||
| 267 | pf.producer.ops->ack_fault(&pf, err); | 267 | pf.producer.ops->ack_fault(&pf, err); |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | 9 | ||
| 10 | #include <generated/xe_wa_oob.h> | 10 | #include <generated/xe_wa_oob.h> |
| 11 | 11 | ||
| 12 | #include "regs/xe_gt_regs.h" | ||
| 12 | #include "regs/xe_reg_defs.h" | 13 | #include "regs/xe_reg_defs.h" |
| 13 | #include "xe_assert.h" | 14 | #include "xe_assert.h" |
| 14 | #include "xe_device.h" | 15 | #include "xe_device.h" |
| @@ -50,8 +51,37 @@ · 35 unmodified lines | |||
| 50 | #define XELP_PAT_WC REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 1) | 51 | #define XELP_PAT_WC REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 1) |
| 51 | #define XELP_PAT_UC REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 0) | 52 | #define XELP_PAT_UC REG_FIELD_PREP(XELP_MEM_TYPE_MASK, 0) |
| 52 | 53 | ||
| 54 | #define PAT_LABEL_LEN 20 | ||
| 55 | |||
| 53 | static const char *XELP_MEM_TYPE_STR_MAP[] = { "UC", "WC", "WT", "WB" }; | 56 | static const char *XELP_MEM_TYPE_STR_MAP[] = { "UC", "WC", "WT", "WB" }; |
| 54 | 57 | ||
| 58 | static void xe_pat_index_label(char *label, size_t len, int index) | ||
| 59 | { | ||
| 60 | snprintf(label, len, "PAT[%2d] ", index); | ||
| 61 | } | ||
| 62 | |||
| 63 | static void xelp_pat_entry_dump(struct drm_printer *p, int index, u32 pat) | ||
| 64 | { | ||
| 65 | u8 mem_type = REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat); | ||
| 66 | |||
| 67 | drm_printf(p, "PAT[%2d] = %s (%#8x)\n", index, | ||
| 68 | XELP_MEM_TYPE_STR_MAP[mem_type], pat); | ||
| 69 | } | ||
| 70 | |||
| 71 | static void xehpc_pat_entry_dump(struct drm_printer *p, int index, u32 pat) | ||
| 72 | { | ||
| 73 | drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", index, | ||
| 74 | REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat), | ||
| 75 | REG_FIELD_GET(XEHPC_CLOS_LEVEL_MASK, pat), pat); | ||
| 76 | } | ||
| 77 | |||
| 78 | static void xelpg_pat_entry_dump(struct drm_printer *p, int index, u32 pat) | ||
| 79 | { | ||
| 80 | drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", index, | ||
| 81 | REG_FIELD_GET(XELPG_L4_POLICY_MASK, pat), | ||
| 82 | REG_FIELD_GET(XELPG_INDEX_COH_MODE_MASK, pat), pat); | ||
| 83 | } | ||
| 84 | |||
| 55 | struct xe_pat_ops { | 85 | struct xe_pat_ops { |
| 56 | void (*program_graphics)(struct xe_gt *gt, const struct xe_pat_table_entry table[], | 86 | void (*program_graphics)(struct xe_gt *gt, const struct xe_pat_table_entry table[], |
| 57 | int n_entries); | 87 | int n_entries); |
| @@ -196,6 +226,19 @@ u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index) · 138 unmodified lines | |||
| 196 | return xe->pat.table[pat_index].coh_mode; | 226 | return xe->pat.table[pat_index].coh_mode; |
| 197 | } | 227 | } |
| 198 | 228 | ||
| 229 | bool xe_pat_index_get_comp_en(struct xe_device *xe, u16 pat_index) | ||
| 230 | { | ||
| 231 | WARN_ON(pat_index >= xe->pat.n_entries); | ||
| 232 | return !!(xe->pat.table[pat_index].value & XE2_COMP_EN); | ||
| 233 | } | ||
| 234 | |||
| 235 | u16 xe_pat_index_get_l3_policy(struct xe_device *xe, u16 pat_index) | ||
| 236 | { | ||
| 237 | WARN_ON(pat_index >= xe->pat.n_entries); | ||
| 238 | |||
| 239 | return REG_FIELD_GET(XE2_L3_POLICY, xe->pat.table[pat_index].value); | ||
| 240 | } | ||
| 241 | |||
| 199 | static void program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[], | 242 | static void program_pat(struct xe_gt *gt, const struct xe_pat_table_entry table[], |
| 200 | int n_entries) | 243 | int n_entries) |
| 201 | { | 244 | { |
| @@ -233,24 +276,20 @@ static void program_pat_mcr(struct xe_gt *gt, const struct xe_pat_table_entry ta · 31 unmodified lines | |||
| 233 | static int xelp_dump(struct xe_gt *gt, struct drm_printer *p) | 276 | static int xelp_dump(struct xe_gt *gt, struct drm_printer *p) |
| 234 | { | 277 | { |
| 235 | struct xe_device *xe = gt_to_xe(gt); | 278 | struct xe_device *xe = gt_to_xe(gt); |
| 236 | unsigned int fw_ref; | ||
| 237 | int i; | 279 | int i; |
| 238 | 280 | ||
| 239 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 281 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 240 | if (!fw_ref) | 282 | if (!fw_ref.domains) |
| 241 | return -ETIMEDOUT; | 283 | return -ETIMEDOUT; |
| 242 | 284 | ||
| 243 | drm_printf(p, "PAT table:\n"); | 285 | drm_printf(p, "PAT table:\n"); |
| 244 | 286 | ||
| 245 | for (i = 0; i < xe->pat.n_entries; i++) { | 287 | for (i = 0; i < xe->pat.n_entries; i++) { |
| 246 | u32 pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_INDEX(i))); | 288 | u32 pat = xe_mmio_read32(>->mmio, XE_REG(_PAT_INDEX(i))); |
| 247 | u8 mem_type = REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat); | ||
| 248 | 289 | ||
| 249 | drm_printf(p, "PAT[%2d] = %s (%#8x)\n", i, | 290 | xelp_pat_entry_dump(p, i, pat); |
| 250 | XELP_MEM_TYPE_STR_MAP[mem_type], pat); | ||
| 251 | } | 291 | } |
| 252 | 292 | ||
| 253 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 254 | return 0; | 293 | return 0; |
| 255 | } | 294 | } |
| 256 | 295 | ||
| @@ -262,26 +301,20 @@ static const struct xe_pat_ops xelp_pat_ops = { · 5 unmodified lines | |||
| 262 | static int xehp_dump(struct xe_gt *gt, struct drm_printer *p) | 301 | static int xehp_dump(struct xe_gt *gt, struct drm_printer *p) |
| 263 | { | 302 | { |
| 264 | struct xe_device *xe = gt_to_xe(gt); | 303 | struct xe_device *xe = gt_to_xe(gt); |
| 265 | unsigned int fw_ref; | ||
| 266 | int i; | 304 | int i; |
| 267 | 305 | ||
| 268 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 306 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 269 | if (!fw_ref) | 307 | if (!fw_ref.domains) |
| 270 | return -ETIMEDOUT; | 308 | return -ETIMEDOUT; |
| 271 | 309 | ||
| 272 | drm_printf(p, "PAT table:\n"); | 310 | drm_printf(p, "PAT table:\n"); |
| 273 | 311 | ||
| 274 | for (i = 0; i < xe->pat.n_entries; i++) { | 312 | for (i = 0; i < xe->pat.n_entries; i++) { |
| 275 | u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); | 313 | u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); |
| 276 | u8 mem_type; | ||
| 277 | |||
| 278 | mem_type = REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat); | ||
| 279 | 314 | ||
| 280 | drm_printf(p, "PAT[%2d] = %s (%#8x)\n", i, | 315 | xelp_pat_entry_dump(p, i, pat); |
| 281 | XELP_MEM_TYPE_STR_MAP[mem_type], pat); | ||
| 282 | } | 316 | } |
| 283 | 317 | ||
| 284 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 285 | return 0; | 318 | return 0; |
| 286 | } | 319 | } |
| 287 | 320 | ||
| @@ -293,11 +326,10 @@ static const struct xe_pat_ops xehp_pat_ops = { · 5 unmodified lines | |||
| 293 | static int xehpc_dump(struct xe_gt *gt, struct drm_printer *p) | 326 | static int xehpc_dump(struct xe_gt *gt, struct drm_printer *p) |
| 294 | { | 327 | { |
| 295 | struct xe_device *xe = gt_to_xe(gt); | 328 | struct xe_device *xe = gt_to_xe(gt); |
| 296 | unsigned int fw_ref; | ||
| 297 | int i; | 329 | int i; |
| 298 | 330 | ||
| 299 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 331 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 300 | if (!fw_ref) | 332 | if (!fw_ref.domains) |
| 301 | return -ETIMEDOUT; | 333 | return -ETIMEDOUT; |
| 302 | 334 | ||
| 303 | drm_printf(p, "PAT table:\n"); | 335 | drm_printf(p, "PAT table:\n"); |
| @@ -305,12 +337,9 @@ static int xehpc_dump(struct xe_gt *gt, struct drm_printer *p) · 1 unmodified line | |||
| 305 | for (i = 0; i < xe->pat.n_entries; i++) { | 337 | for (i = 0; i < xe->pat.n_entries; i++) { |
| 306 | u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); | 338 | u32 pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); |
| 307 | 339 | ||
| 308 | drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", i, | 340 | xehpc_pat_entry_dump(p, i, pat); |
| 309 | REG_FIELD_GET(XELP_MEM_TYPE_MASK, pat), | ||
| 310 | REG_FIELD_GET(XEHPC_CLOS_LEVEL_MASK, pat), pat); | ||
| 311 | } | 341 | } |
| 312 | 342 | ||
| 313 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 314 | return 0; | 343 | return 0; |
| 315 | } | 344 | } |
| 316 | 345 | ||
| @@ -322,11 +351,10 @@ static const struct xe_pat_ops xehpc_pat_ops = { · 5 unmodified lines | |||
| 322 | static int xelpg_dump(struct xe_gt *gt, struct drm_printer *p) | 351 | static int xelpg_dump(struct xe_gt *gt, struct drm_printer *p) |
| 323 | { | 352 | { |
| 324 | struct xe_device *xe = gt_to_xe(gt); | 353 | struct xe_device *xe = gt_to_xe(gt); |
| 325 | unsigned int fw_ref; | ||
| 326 | int i; | 354 | int i; |
| 327 | 355 | ||
| 328 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 356 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 329 | if (!fw_ref) | 357 | if (!fw_ref.domains) |
| 330 | return -ETIMEDOUT; | 358 | return -ETIMEDOUT; |
| 331 | 359 | ||
| 332 | drm_printf(p, "PAT table:\n"); | 360 | drm_printf(p, "PAT table:\n"); |
| @@ -339,12 +367,9 @@ static int xelpg_dump(struct xe_gt *gt, struct drm_printer *p) · 6 unmodified lines | |||
| 339 | else | 367 | else |
| 340 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); | 368 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); |
| 341 | 369 | ||
| 342 | drm_printf(p, "PAT[%2d] = [ %u, %u ] (%#8x)\n", i, | 370 | xelpg_pat_entry_dump(p, i, pat); |
| 343 | REG_FIELD_GET(XELPG_L4_POLICY_MASK, pat), | ||
| 344 | REG_FIELD_GET(XELPG_INDEX_COH_MODE_MASK, pat), pat); | ||
| 345 | } | 371 | } |
| 346 | 372 | ||
| 347 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 348 | return 0; | 373 | return 0; |
| 349 | } | 374 | } |
| 350 | 375 | ||
| @@ -358,15 +383,38 @@ static const struct xe_pat_ops xelpg_pat_ops = { · 7 unmodified lines | |||
| 358 | .dump = xelpg_dump, | 383 | .dump = xelpg_dump, |
| 359 | }; | 384 | }; |
| 360 | 385 | ||
| 386 | static void xe2_pat_entry_dump(struct drm_printer *p, const char *label, u32 pat, bool rsvd) | ||
| 387 | { | ||
| 388 | drm_printf(p, "%s= [ %u, %u, %u, %u, %u, %u ] (%#8x)%s\n", label, | ||
| 389 | !!(pat & XE2_NO_PROMOTE), | ||
| 390 | !!(pat & XE2_COMP_EN), | ||
| 391 | REG_FIELD_GET(XE2_L3_CLOS, pat), | ||
| 392 | REG_FIELD_GET(XE2_L3_POLICY, pat), | ||
| 393 | REG_FIELD_GET(XE2_L4_POLICY, pat), | ||
| 394 | REG_FIELD_GET(XE2_COH_MODE, pat), | ||
| 395 | pat, rsvd ? " *" : ""); | ||
| 396 | } | ||
| 397 | |||
| 398 | static void xe3p_xpc_pat_entry_dump(struct drm_printer *p, const char *label, u32 pat, bool rsvd) | ||
| 399 | { | ||
| 400 | drm_printf(p, "%s= [ %u, %u, %u, %u, %u ] (%#8x)%s\n", label, | ||
| 401 | !!(pat & XE2_NO_PROMOTE), | ||
| 402 | REG_FIELD_GET(XE2_L3_CLOS, pat), | ||
| 403 | REG_FIELD_GET(XE2_L3_POLICY, pat), | ||
| 404 | REG_FIELD_GET(XE2_L4_POLICY, pat), | ||
| 405 | REG_FIELD_GET(XE2_COH_MODE, pat), | ||
| 406 | pat, rsvd ? " *" : ""); | ||
| 407 | } | ||
| 408 | |||
| 361 | static int xe2_dump(struct xe_gt *gt, struct drm_printer *p) | 409 | static int xe2_dump(struct xe_gt *gt, struct drm_printer *p) |
| 362 | { | 410 | { |
| 363 | struct xe_device *xe = gt_to_xe(gt); | 411 | struct xe_device *xe = gt_to_xe(gt); |
| 364 | unsigned int fw_ref; | ||
| 365 | u32 pat; | 412 | u32 pat; |
| 366 | int i; | 413 | int i; |
| 414 | char label[PAT_LABEL_LEN]; | ||
| 367 | 415 | ||
| 368 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 416 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 369 | if (!fw_ref) | 417 | if (!fw_ref.domains) |
| 370 | return -ETIMEDOUT; | 418 | return -ETIMEDOUT; |
| 371 | 419 | ||
| 372 | drm_printf(p, "PAT table: (* = reserved entry)\n"); | 420 | drm_printf(p, "PAT table: (* = reserved entry)\n"); |
| @@ -377,14 +425,8 @@ static int xe2_dump(struct xe_gt *gt, struct drm_printer *p) · 4 unmodified lines | |||
| 377 | else | 425 | else |
| 378 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); | 426 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); |
| 379 | 427 | ||
| 380 | drm_printf(p, "PAT[%2d] = [ %u, %u, %u, %u, %u, %u ] (%#8x)%s\n", i, | 428 | xe_pat_index_label(label, sizeof(label), i); |
| 381 | !!(pat & XE2_NO_PROMOTE), | 429 | xe2_pat_entry_dump(p, label, pat, !xe->pat.table[i].valid); |
| 382 | !!(pat & XE2_COMP_EN), | ||
| 383 | REG_FIELD_GET(XE2_L3_CLOS, pat), | ||
| 384 | REG_FIELD_GET(XE2_L3_POLICY, pat), | ||
| 385 | REG_FIELD_GET(XE2_L4_POLICY, pat), | ||
| 386 | REG_FIELD_GET(XE2_COH_MODE, pat), | ||
| 387 | pat, xe->pat.table[i].valid ? "" : " *"); | ||
| 388 | } | 430 | } |
| 389 | 431 | ||
| 390 | /* | 432 | /* |
| @@ -397,16 +439,8 @@ static int xe2_dump(struct xe_gt *gt, struct drm_printer *p) · 6 unmodified lines | |||
| 397 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_PTA)); | 439 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_PTA)); |
| 398 | 440 | ||
| 399 | drm_printf(p, "Page Table Access:\n"); | 441 | drm_printf(p, "Page Table Access:\n"); |
| 400 | drm_printf(p, "PTA_MODE= [ %u, %u, %u, %u, %u, %u ] (%#8x)\n", | 442 | xe2_pat_entry_dump(p, "PTA_MODE", pat, false); |
| 401 | !!(pat & XE2_NO_PROMOTE), | ||
| 402 | !!(pat & XE2_COMP_EN), | ||
| 403 | REG_FIELD_GET(XE2_L3_CLOS, pat), | ||
| 404 | REG_FIELD_GET(XE2_L3_POLICY, pat), | ||
| 405 | REG_FIELD_GET(XE2_L4_POLICY, pat), | ||
| 406 | REG_FIELD_GET(XE2_COH_MODE, pat), | ||
| 407 | pat); | ||
| 408 | 443 | ||
| 409 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 410 | return 0; | 444 | return 0; |
| 411 | } | 445 | } |
| 412 | 446 | ||
| @@ -419,12 +453,12 @@ static const struct xe_pat_ops xe2_pat_ops = { · 6 unmodified lines | |||
| 419 | static int xe3p_xpc_dump(struct xe_gt *gt, struct drm_printer *p) | 453 | static int xe3p_xpc_dump(struct xe_gt *gt, struct drm_printer *p) |
| 420 | { | 454 | { |
| 421 | struct xe_device *xe = gt_to_xe(gt); | 455 | struct xe_device *xe = gt_to_xe(gt); |
| 422 | unsigned int fw_ref; | ||
| 423 | u32 pat; | 456 | u32 pat; |
| 424 | int i; | 457 | int i; |
| 458 | char label[PAT_LABEL_LEN]; | ||
| 425 | 459 | ||
| 426 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 460 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 427 | if (!fw_ref) | 461 | if (!fw_ref.domains) |
| 428 | return -ETIMEDOUT; | 462 | return -ETIMEDOUT; |
| 429 | 463 | ||
| 430 | drm_printf(p, "PAT table: (* = reserved entry)\n"); | 464 | drm_printf(p, "PAT table: (* = reserved entry)\n"); |
| @@ -432,13 +466,8 @@ static int xe3p_xpc_dump(struct xe_gt *gt, struct drm_printer *p) · 1 unmodified line | |||
| 432 | for (i = 0; i < xe->pat.n_entries; i++) { | 466 | for (i = 0; i < xe->pat.n_entries; i++) { |
| 433 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); | 467 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_INDEX(i))); |
| 434 | 468 | ||
| 435 | drm_printf(p, "PAT[%2d] = [ %u, %u, %u, %u, %u ] (%#8x)%s\n", i, | 469 | xe_pat_index_label(label, sizeof(label), i); |
| 436 | !!(pat & XE2_NO_PROMOTE), | 470 | xe3p_xpc_pat_entry_dump(p, label, pat, !xe->pat.table[i].valid); |
| 437 | REG_FIELD_GET(XE2_L3_CLOS, pat), | ||
| 438 | REG_FIELD_GET(XE2_L3_POLICY, pat), | ||
| 439 | REG_FIELD_GET(XE2_L4_POLICY, pat), | ||
| 440 | REG_FIELD_GET(XE2_COH_MODE, pat), | ||
| 441 | pat, xe->pat.table[i].valid ? "" : " *"); | ||
| 442 | } | 471 | } |
| 443 | 472 | ||
| 444 | /* | 473 | /* |
| @@ -448,15 +477,8 @@ static int xe3p_xpc_dump(struct xe_gt *gt, struct drm_printer *p) · 3 unmodified lines | |||
| 448 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_PTA)); | 477 | pat = xe_gt_mcr_unicast_read_any(gt, XE_REG_MCR(_PAT_PTA)); |
| 449 | 478 | ||
| 450 | drm_printf(p, "Page Table Access:\n"); | 479 | drm_printf(p, "Page Table Access:\n"); |
| 451 | drm_printf(p, "PTA_MODE= [ %u, %u, %u, %u, %u ] (%#8x)\n", | 480 | xe3p_xpc_pat_entry_dump(p, "PTA_MODE", pat, false); |
| 452 | !!(pat & XE2_NO_PROMOTE), | ||
| 453 | REG_FIELD_GET(XE2_L3_CLOS, pat), | ||
| 454 | REG_FIELD_GET(XE2_L3_POLICY, pat), | ||
| 455 | REG_FIELD_GET(XE2_L4_POLICY, pat), | ||
| 456 | REG_FIELD_GET(XE2_COH_MODE, pat), | ||
| 457 | pat); | ||
| 458 | 481 | ||
| 459 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 460 | return 0; | 482 | return 0; |
| 461 | } | 483 | } |
| 462 | 484 | ||
| @@ -578,3 +600,65 @@ int xe_pat_dump(struct xe_gt *gt, struct drm_printer *p) · 115 unmodified lines | |||
| 578 | 600 | ||
| 579 | return xe->pat.ops->dump(gt, p); | 601 | return xe->pat.ops->dump(gt, p); |
| 580 | } | 602 | } |
| 603 | |||
| 604 | /** | ||
| 605 | * xe_pat_dump_sw_config() - Dump the software-configured GT PAT table into a drm printer. | ||
| 606 | * @gt: the &xe_gt | ||
| 607 | * @p: the &drm_printer | ||
| 608 | * | ||
| 609 | * Return: 0 on success or a negative error code on failure. | ||
| 610 | */ | ||
| 611 | int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p) | ||
| 612 | { | ||
| 613 | struct xe_device *xe = gt_to_xe(gt); | ||
| 614 | char label[PAT_LABEL_LEN]; | ||
| 615 | |||
| 616 | if (!xe->pat.table || !xe->pat.n_entries) | ||
| 617 | return -EOPNOTSUPP; | ||
| 618 | |||
| 619 | drm_printf(p, "PAT table:%s\n", GRAPHICS_VER(xe) >= 20 ? " (* = reserved entry)" : ""); | ||
| 620 | for (u32 i = 0; i < xe->pat.n_entries; i++) { | ||
| 621 | u32 pat = xe->pat.table[i].value; | ||
| 622 | |||
| 623 | if (GRAPHICS_VERx100(xe) == 3511) { | ||
| 624 | xe_pat_index_label(label, sizeof(label), i); | ||
| 625 | xe3p_xpc_pat_entry_dump(p, label, pat, !xe->pat.table[i].valid); | ||
| 626 | } else if (GRAPHICS_VER(xe) == 30 || GRAPHICS_VER(xe) == 20) { | ||
| 627 | xe_pat_index_label(label, sizeof(label), i); | ||
| 628 | xe2_pat_entry_dump(p, label, pat, !xe->pat.table[i].valid); | ||
| 629 | } else if (xe->info.platform == XE_METEORLAKE) { | ||
| 630 | xelpg_pat_entry_dump(p, i, pat); | ||
| 631 | } else if (xe->info.platform == XE_PVC) { | ||
| 632 | xehpc_pat_entry_dump(p, i, pat); | ||
| 633 | } else if (xe->info.platform == XE_DG2 || GRAPHICS_VERx100(xe) <= 1210) { | ||
| 634 | xelp_pat_entry_dump(p, i, pat); | ||
| 635 | } else { | ||
| 636 | return -EOPNOTSUPP; | ||
| 637 | } | ||
| 638 | } | ||
| 639 | |||
| 640 | if (xe->pat.pat_pta) { | ||
| 641 | u32 pat = xe->pat.pat_pta->value; | ||
| 642 | |||
| 643 | drm_printf(p, "Page Table Access:\n"); | ||
| 644 | xe2_pat_entry_dump(p, "PTA_MODE", pat, false); | ||
| 645 | } | ||
| 646 | |||
| 647 | if (xe->pat.pat_ats) { | ||
| 648 | u32 pat = xe->pat.pat_ats->value; | ||
| 649 | |||
| 650 | drm_printf(p, "PCIe ATS/PASID:\n"); | ||
| 651 | xe2_pat_entry_dump(p, "PAT_ATS ", pat, false); | ||
| 652 | } | ||
| 653 | |||
| 654 | drm_printf(p, "Cache Level:\n"); | ||
| 655 | drm_printf(p, "IDX[XE_CACHE_NONE] = %d\n", xe->pat.idx[XE_CACHE_NONE]); | ||
| 656 | drm_printf(p, "IDX[XE_CACHE_WT] = %d\n", xe->pat.idx[XE_CACHE_WT]); | ||
| 657 | drm_printf(p, "IDX[XE_CACHE_WB] = %d\n", xe->pat.idx[XE_CACHE_WB]); | ||
| 658 | if (GRAPHICS_VER(xe) >= 20) { | ||
| 659 | drm_printf(p, "IDX[XE_CACHE_NONE_COMPRESSION] = %d\n", | ||
| 660 | xe->pat.idx[XE_CACHE_NONE_COMPRESSION]); | ||
| 661 | } | ||
| 662 | |||
| 663 | return 0; | ||
| 664 | } | ||
| @@ -49,6 +49,7 @@ void xe_pat_init_early(struct xe_device *xe); · 48 unmodified lines | |||
| 49 | void xe_pat_init(struct xe_gt *gt); | 49 | void xe_pat_init(struct xe_gt *gt); |
| 50 | 50 | ||
| 51 | int xe_pat_dump(struct xe_gt *gt, struct drm_printer *p); | 51 | int xe_pat_dump(struct xe_gt *gt, struct drm_printer *p); |
| 52 | int xe_pat_dump_sw_config(struct xe_gt *gt, struct drm_printer *p); | ||
| 52 | 53 | ||
| 53 | /** | 54 | /** |
| 54 | * xe_pat_index_get_coh_mode - Extract the coherency mode for the given | 55 | * xe_pat_index_get_coh_mode - Extract the coherency mode for the given |
| @@ -58,4 +59,24 @@ int xe_pat_dump(struct xe_gt *gt, struct drm_printer *p); · 3 unmodified lines | |||
| 58 | */ | 59 | */ |
| 59 | u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index); | 60 | u16 xe_pat_index_get_coh_mode(struct xe_device *xe, u16 pat_index); |
| 60 | 61 | ||
| 62 | /** | ||
| 63 | * xe_pat_index_get_comp_en - Extract the compression enable flag for | ||
| 64 | * the given pat_index. | ||
| 65 | * @xe: xe device | ||
| 66 | * @pat_index: The pat_index to query | ||
| 67 | * | ||
| 68 | * Return: true if compression is enabled for this pat_index, false otherwise. | ||
| 69 | */ | ||
| 70 | bool xe_pat_index_get_comp_en(struct xe_device *xe, u16 pat_index); | ||
| 71 | |||
| 72 | #define XE_L3_POLICY_WB 0 /* Write-back */ | ||
| 73 | #define XE_L3_POLICY_XD 1 /* WB - Transient Display */ | ||
| 74 | #define XE_L3_POLICY_UC 3 /* Uncached */ | ||
| 75 | /** | ||
| 76 | * xe_pat_index_get_l3_policy - Extract the L3 policy for the given pat_index. | ||
| 77 | * @xe: xe device | ||
| 78 | * @pat_index: The pat_index to query | ||
| 79 | */ | ||
| 80 | u16 xe_pat_index_get_l3_policy(struct xe_device *xe, u16 pat_index); | ||
| 81 | |||
| 61 | #endif | 82 | #endif |
| @@ -108,6 +108,7 @@ static const struct xe_graphics_desc graphics_xe2 = { · 107 unmodified lines | |||
| 108 | 108 | ||
| 109 | static const struct xe_graphics_desc graphics_xe3p_xpc = { | 109 | static const struct xe_graphics_desc graphics_xe3p_xpc = { |
| 110 | XE2_GFX_FEATURES, | 110 | XE2_GFX_FEATURES, |
| 111 | .has_indirect_ring_state = 1, | ||
| 111 | .hw_engine_mask = | 112 | .hw_engine_mask = |
| 112 | GENMASK(XE_HW_ENGINE_BCS8, XE_HW_ENGINE_BCS1) | | 113 | GENMASK(XE_HW_ENGINE_BCS8, XE_HW_ENGINE_BCS1) | |
| 113 | GENMASK(XE_HW_ENGINE_CCS3, XE_HW_ENGINE_CCS0), | 114 | GENMASK(XE_HW_ENGINE_CCS3, XE_HW_ENGINE_CCS0), |
| @@ -168,6 +169,7 @@ static const struct xe_device_desc tgl_desc = { · 54 unmodified lines | |||
| 168 | .pre_gmdid_media_ip = &media_ip_xem, | 169 | .pre_gmdid_media_ip = &media_ip_xem, |
| 169 | PLATFORM(TIGERLAKE), | 170 | PLATFORM(TIGERLAKE), |
| 170 | .dma_mask_size = 39, | 171 | .dma_mask_size = 39, |
| 172 | .has_cached_pt = true, | ||
| 171 | .has_display = true, | 173 | .has_display = true, |
| 172 | .has_llc = true, | 174 | .has_llc = true, |
| 173 | .has_sriov = true, | 175 | .has_sriov = true, |
| @@ -182,6 +184,7 @@ static const struct xe_device_desc rkl_desc = { · 8 unmodified lines | |||
| 182 | .pre_gmdid_media_ip = &media_ip_xem, | 184 | .pre_gmdid_media_ip = &media_ip_xem, |
| 183 | PLATFORM(ROCKETLAKE), | 185 | PLATFORM(ROCKETLAKE), |
| 184 | .dma_mask_size = 39, | 186 | .dma_mask_size = 39, |
| 187 | .has_cached_pt = true, | ||
| 185 | .has_display = true, | 188 | .has_display = true, |
| 186 | .has_llc = true, | 189 | .has_llc = true, |
| 187 | .max_gt_per_tile = 1, | 190 | .max_gt_per_tile = 1, |
| @@ -197,6 +200,7 @@ static const struct xe_device_desc adl_s_desc = { · 9 unmodified lines | |||
| 197 | .pre_gmdid_media_ip = &media_ip_xem, | 200 | .pre_gmdid_media_ip = &media_ip_xem, |
| 198 | PLATFORM(ALDERLAKE_S), | 201 | PLATFORM(ALDERLAKE_S), |
| 199 | .dma_mask_size = 39, | 202 | .dma_mask_size = 39, |
| 203 | .has_cached_pt = true, | ||
| 200 | .has_display = true, | 204 | .has_display = true, |
| 201 | .has_llc = true, | 205 | .has_llc = true, |
| 202 | .has_sriov = true, | 206 | .has_sriov = true, |
| @@ -217,6 +221,7 @@ static const struct xe_device_desc adl_p_desc = { · 14 unmodified lines | |||
| 217 | .pre_gmdid_media_ip = &media_ip_xem, | 221 | .pre_gmdid_media_ip = &media_ip_xem, |
| 218 | PLATFORM(ALDERLAKE_P), | 222 | PLATFORM(ALDERLAKE_P), |
| 219 | .dma_mask_size = 39, | 223 | .dma_mask_size = 39, |
| 224 | .has_cached_pt = true, | ||
| 220 | .has_display = true, | 225 | .has_display = true, |
| 221 | .has_llc = true, | 226 | .has_llc = true, |
| 222 | .has_sriov = true, | 227 | .has_sriov = true, |
| @@ -235,6 +240,7 @@ static const struct xe_device_desc adl_n_desc = { · 12 unmodified lines | |||
| 235 | .pre_gmdid_media_ip = &media_ip_xem, | 240 | .pre_gmdid_media_ip = &media_ip_xem, |
| 236 | PLATFORM(ALDERLAKE_N), | 241 | PLATFORM(ALDERLAKE_N), |
| 237 | .dma_mask_size = 39, | 242 | .dma_mask_size = 39, |
| 243 | .has_cached_pt = true, | ||
| 238 | .has_display = true, | 244 | .has_display = true, |
| 239 | .has_llc = true, | 245 | .has_llc = true, |
| 240 | .has_sriov = true, | 246 | .has_sriov = true, |
| @@ -361,7 +367,9 @@ static const struct xe_device_desc bmg_desc = { · 120 unmodified lines | |||
| 361 | .has_mbx_power_limits = true, | 367 | .has_mbx_power_limits = true, |
| 362 | .has_gsc_nvm = 1, | 368 | .has_gsc_nvm = 1, |
| 363 | .has_heci_cscfi = 1, | 369 | .has_heci_cscfi = 1, |
| 370 | .has_i2c = true, | ||
| 364 | .has_late_bind = true, | 371 | .has_late_bind = true, |
| 372 | .has_pre_prod_wa = 1, | ||
| 365 | .has_sriov = true, | 373 | .has_sriov = true, |
| 366 | .has_mem_copy_instr = true, | 374 | .has_mem_copy_instr = true, |
| 367 | .max_gt_per_tile = 2, | 375 | .max_gt_per_tile = 2, |
| @@ -381,6 +389,7 @@ static const struct xe_device_desc ptl_desc = { · 13 unmodified lines | |||
| 381 | .has_flat_ccs = 1, | 389 | .has_flat_ccs = 1, |
| 382 | .has_sriov = true, | 390 | .has_sriov = true, |
| 383 | .has_mem_copy_instr = true, | 391 | .has_mem_copy_instr = true, |
| 392 | .has_pre_prod_wa = 1, | ||
| 384 | .max_gt_per_tile = 2, | 393 | .max_gt_per_tile = 2, |
| 385 | .needs_scratch = true, | 394 | .needs_scratch = true, |
| 386 | .needs_shared_vf_gt_wq = true, | 395 | .needs_shared_vf_gt_wq = true, |
| @@ -394,6 +403,7 @@ static const struct xe_device_desc nvls_desc = { · 7 unmodified lines | |||
| 394 | .has_display = true, | 403 | .has_display = true, |
| 395 | .has_flat_ccs = 1, | 404 | .has_flat_ccs = 1, |
| 396 | .has_mem_copy_instr = true, | 405 | .has_mem_copy_instr = true, |
| 406 | .has_pre_prod_wa = 1, | ||
| 397 | .max_gt_per_tile = 2, | 407 | .max_gt_per_tile = 2, |
| 398 | .require_force_probe = true, | 408 | .require_force_probe = true, |
| 399 | .va_bits = 48, | 409 | .va_bits = 48, |
| @@ -406,7 +416,11 @@ static const struct xe_device_desc cri_desc = { · 6 unmodified lines | |||
| 406 | .dma_mask_size = 52, | 416 | .dma_mask_size = 52, |
| 407 | .has_display = false, | 417 | .has_display = false, |
| 408 | .has_flat_ccs = false, | 418 | .has_flat_ccs = false, |
| 419 | .has_gsc_nvm = 1, | ||
| 420 | .has_i2c = true, | ||
| 409 | .has_mbx_power_limits = true, | 421 | .has_mbx_power_limits = true, |
| 422 | .has_mert = true, | ||
| 423 | .has_pre_prod_wa = 1, | ||
| 410 | .has_sriov = true, | 424 | .has_sriov = true, |
| 411 | .max_gt_per_tile = 2, | 425 | .max_gt_per_tile = 2, |
| 412 | .require_force_probe = true, | 426 | .require_force_probe = true, |
| @@ -663,6 +677,7 @@ static int xe_info_init_early(struct xe_device *xe, · 250 unmodified lines | |||
| 663 | xe->info.vram_flags = desc->vram_flags; | 677 | xe->info.vram_flags = desc->vram_flags; |
| 664 | 678 | ||
| 665 | xe->info.is_dgfx = desc->is_dgfx; | 679 | xe->info.is_dgfx = desc->is_dgfx; |
| 680 | xe->info.has_cached_pt = desc->has_cached_pt; | ||
| 666 | xe->info.has_fan_control = desc->has_fan_control; | 681 | xe->info.has_fan_control = desc->has_fan_control; |
| 667 | /* runtime fusing may force flat_ccs to disabled later */ | 682 | /* runtime fusing may force flat_ccs to disabled later */ |
| 668 | xe->info.has_flat_ccs = desc->has_flat_ccs; | 683 | xe->info.has_flat_ccs = desc->has_flat_ccs; |
| @@ -670,8 +685,12 @@ static int xe_info_init_early(struct xe_device *xe, · 1 unmodified line | |||
| 670 | xe->info.has_gsc_nvm = desc->has_gsc_nvm; | 685 | xe->info.has_gsc_nvm = desc->has_gsc_nvm; |
| 671 | xe->info.has_heci_gscfi = desc->has_heci_gscfi; | 686 | xe->info.has_heci_gscfi = desc->has_heci_gscfi; |
| 672 | xe->info.has_heci_cscfi = desc->has_heci_cscfi; | 687 | xe->info.has_heci_cscfi = desc->has_heci_cscfi; |
| 688 | xe->info.has_i2c = desc->has_i2c; | ||
| 673 | xe->info.has_late_bind = desc->has_late_bind; | 689 | xe->info.has_late_bind = desc->has_late_bind; |
| 674 | xe->info.has_llc = desc->has_llc; | 690 | xe->info.has_llc = desc->has_llc; |
| 691 | xe->info.has_mert = desc->has_mert; | ||
| 692 | xe->info.has_page_reclaim_hw_assist = desc->has_page_reclaim_hw_assist; | ||
| 693 | xe->info.has_pre_prod_wa = desc->has_pre_prod_wa; | ||
| 675 | xe->info.has_pxp = desc->has_pxp; | 694 | xe->info.has_pxp = desc->has_pxp; |
| 676 | xe->info.has_sriov = xe_configfs_primary_gt_allowed(to_pci_dev(xe->drm.dev)) && | 695 | xe->info.has_sriov = xe_configfs_primary_gt_allowed(to_pci_dev(xe->drm.dev)) && |
| 677 | desc->has_sriov; | 696 | desc->has_sriov; |
| @@ -755,6 +774,7 @@ static struct xe_gt *alloc_primary_gt(struct xe_tile *tile, · 77 unmodified lines | |||
| 755 | gt->info.type = XE_GT_TYPE_MAIN; | 774 | gt->info.type = XE_GT_TYPE_MAIN; |
| 756 | gt->info.id = tile->id * xe->info.max_gt_per_tile; | 775 | gt->info.id = tile->id * xe->info.max_gt_per_tile; |
| 757 | gt->info.has_indirect_ring_state = graphics_desc->has_indirect_ring_state; | 776 | gt->info.has_indirect_ring_state = graphics_desc->has_indirect_ring_state; |
| 777 | gt->info.multi_queue_engine_class_mask = graphics_desc->multi_queue_engine_class_mask; | ||
| 758 | gt->info.engine_mask = graphics_desc->hw_engine_mask; | 778 | gt->info.engine_mask = graphics_desc->hw_engine_mask; |
| 759 | 779 | ||
| 760 | /* | 780 | /* |
| @@ -1153,6 +1173,15 @@ static int xe_pci_runtime_suspend(struct device *dev) · 392 unmodified lines | |||
| 1153 | struct xe_device *xe = pdev_to_xe_device(pdev); | 1173 | struct xe_device *xe = pdev_to_xe_device(pdev); |
| 1154 | int err; | 1174 | int err; |
| 1155 | 1175 | ||
| 1176 | /* | ||
| 1177 | * We hold an additional reference to the runtime PM to keep PF in D0 | ||
| 1178 | * during VFs lifetime, as our VFs do not implement the PM capability. | ||
| 1179 | * This means we should never be runtime suspending as long as VFs are | ||
| 1180 | * enabled. | ||
| 1181 | */ | ||
| 1182 | xe_assert(xe, !IS_SRIOV_VF(xe)); | ||
| 1183 | xe_assert(xe, !pci_num_vf(pdev)); | ||
| 1184 | |||
| 1156 | err = xe_pm_runtime_suspend(xe); | 1185 | err = xe_pm_runtime_suspend(xe); |
| 1157 | if (err) | 1186 | if (err) |
| 1158 | return err; | 1187 | return err; |
| @@ -219,7 +219,6 @@ static int pf_disable_vfs(struct xe_device *xe) · 218 unmodified lines | |||
| 219 | int xe_pci_sriov_configure(struct pci_dev *pdev, int num_vfs) | 219 | int xe_pci_sriov_configure(struct pci_dev *pdev, int num_vfs) |
| 220 | { | 220 | { |
| 221 | struct xe_device *xe = pdev_to_xe_device(pdev); | 221 | struct xe_device *xe = pdev_to_xe_device(pdev); |
| 222 | int ret; | ||
| 223 | 222 | ||
| 224 | if (!IS_SRIOV_PF(xe)) | 223 | if (!IS_SRIOV_PF(xe)) |
| 225 | return -ENODEV; | 224 | return -ENODEV; |
| @@ -233,14 +232,11 @@ int xe_pci_sriov_configure(struct pci_dev *pdev, int num_vfs) · 7 unmodified lines | |||
| 233 | if (num_vfs && pci_num_vf(pdev)) | 232 | if (num_vfs && pci_num_vf(pdev)) |
| 234 | return -EBUSY; | 233 | return -EBUSY; |
| 235 | 234 | ||
| 236 | xe_pm_runtime_get(xe); | 235 | guard(xe_pm_runtime)(xe); |
| 237 | if (num_vfs > 0) | 236 | if (num_vfs > 0) |
| 238 | ret = pf_enable_vfs(xe, num_vfs); | 237 | return pf_enable_vfs(xe, num_vfs); |
| 239 | else | 238 | else |
| 240 | ret = pf_disable_vfs(xe); | 239 | return pf_disable_vfs(xe); |
| 241 | xe_pm_runtime_put(xe); | ||
| 242 | |||
| 243 | return ret; | ||
| 244 | } | 240 | } |
| 245 | 241 | ||
| 246 | /** | 242 | /** |
| @@ -37,16 +37,21 @@ struct xe_device_desc { · 36 unmodified lines | |||
| 37 | u8 require_force_probe:1; | 37 | u8 require_force_probe:1; |
| 38 | u8 is_dgfx:1; | 38 | u8 is_dgfx:1; |
| 39 | 39 | ||
| 40 | u8 has_cached_pt:1; | ||
| 40 | u8 has_display:1; | 41 | u8 has_display:1; |
| 41 | u8 has_fan_control:1; | 42 | u8 has_fan_control:1; |
| 42 | u8 has_flat_ccs:1; | 43 | u8 has_flat_ccs:1; |
| 43 | u8 has_gsc_nvm:1; | 44 | u8 has_gsc_nvm:1; |
| 44 | u8 has_heci_gscfi:1; | 45 | u8 has_heci_gscfi:1; |
| 45 | u8 has_heci_cscfi:1; | 46 | u8 has_heci_cscfi:1; |
| 47 | u8 has_i2c:1; | ||
| 46 | u8 has_late_bind:1; | 48 | u8 has_late_bind:1; |
| 47 | u8 has_llc:1; | 49 | u8 has_llc:1; |
| 48 | u8 has_mbx_power_limits:1; | 50 | u8 has_mbx_power_limits:1; |
| 49 | u8 has_mem_copy_instr:1; | 51 | u8 has_mem_copy_instr:1; |
| 52 | u8 has_mert:1; | ||
| 53 | u8 has_pre_prod_wa:1; | ||
| 54 | u8 has_page_reclaim_hw_assist:1; | ||
| 50 | u8 has_pxp:1; | 55 | u8 has_pxp:1; |
| 51 | u8 has_sriov:1; | 56 | u8 has_sriov:1; |
| 52 | u8 needs_scratch:1; | 57 | u8 needs_scratch:1; |
| @@ -58,6 +63,7 @@ struct xe_device_desc { · 5 unmodified lines | |||
| 58 | 63 | ||
| 59 | struct xe_graphics_desc { | 64 | struct xe_graphics_desc { |
| 60 | u64 hw_engine_mask; /* hardware engines provided by graphics IP */ | 65 | u64 hw_engine_mask; /* hardware engines provided by graphics IP */ |
| 66 | u16 multi_queue_engine_class_mask; /* bitmask of engine classes which support multi queue */ | ||
| 61 | 67 | ||
| 62 | u8 has_asid:1; | 68 | u8 has_asid:1; |
| 63 | u8 has_atomic_enable_pte_bit:1; | 69 | u8 has_atomic_enable_pte_bit:1; |
| @@ -77,11 +77,13 @@ · 76 unmodified lines | |||
| 77 | 77 | ||
| 78 | #define PCODE_SCRATCH(x) XE_REG(0x138320 + ((x) * 4)) | 78 | #define PCODE_SCRATCH(x) XE_REG(0x138320 + ((x) * 4)) |
| 79 | /* PCODE_SCRATCH0 */ | 79 | /* PCODE_SCRATCH0 */ |
| 80 | #define BREADCRUMB_VERSION REG_GENMASK(31, 29) | ||
| 80 | #define AUXINFO_REG_OFFSET REG_GENMASK(17, 15) | 81 | #define AUXINFO_REG_OFFSET REG_GENMASK(17, 15) |
| 81 | #define OVERFLOW_REG_OFFSET REG_GENMASK(14, 12) | 82 | #define OVERFLOW_REG_OFFSET REG_GENMASK(14, 12) |
| 82 | #define HISTORY_TRACKING REG_BIT(11) | 83 | #define HISTORY_TRACKING REG_BIT(11) |
| 83 | #define OVERFLOW_SUPPORT REG_BIT(10) | 84 | #define OVERFLOW_SUPPORT REG_BIT(10) |
| 84 | #define AUXINFO_SUPPORT REG_BIT(9) | 85 | #define AUXINFO_SUPPORT REG_BIT(9) |
| 86 | #define FDO_MODE REG_BIT(4) | ||
| 85 | #define BOOT_STATUS REG_GENMASK(3, 1) | 87 | #define BOOT_STATUS REG_GENMASK(3, 1) |
| 86 | #define CRITICAL_FAILURE 4 | 88 | #define CRITICAL_FAILURE 4 |
| 87 | #define NON_CRITICAL_FAILURE 7 | 89 | #define NON_CRITICAL_FAILURE 7 |
| @@ -591,7 +591,7 @@ int xe_pm_runtime_suspend(struct xe_device *xe) · 590 unmodified lines | |||
| 591 | } | 591 | } |
| 592 | 592 | ||
| 593 | for_each_gt(gt, xe, id) { | 593 | for_each_gt(gt, xe, id) { |
| 594 | err = xe_gt_suspend(gt); | 594 | err = xe->d3cold.allowed ? xe_gt_suspend(gt) : xe_gt_runtime_suspend(gt); |
| 595 | if (err) | 595 | if (err) |
| 596 | goto out_resume; | 596 | goto out_resume; |
| 597 | } | 597 | } |
| @@ -633,10 +633,10 @@ int xe_pm_runtime_resume(struct xe_device *xe) · 35 unmodified lines | |||
| 633 | 633 | ||
| 634 | xe_rpm_lockmap_acquire(xe); | 634 | xe_rpm_lockmap_acquire(xe); |
| 635 | 635 | ||
| 636 | for_each_gt(gt, xe, id) | ||
| 637 | xe_gt_idle_disable_c6(gt); | ||
| 638 | |||
| 639 | if (xe->d3cold.allowed) { | 636 | if (xe->d3cold.allowed) { |
| 637 | for_each_gt(gt, xe, id) | ||
| 638 | xe_gt_idle_disable_c6(gt); | ||
| 639 | |||
| 640 | err = xe_pcode_ready(xe, true); | 640 | err = xe_pcode_ready(xe, true); |
| 641 | if (err) | 641 | if (err) |
| 642 | goto out; | 642 | goto out; |
| @@ -657,7 +657,7 @@ int xe_pm_runtime_resume(struct xe_device *xe) · 14 unmodified lines | |||
| 657 | xe_irq_resume(xe); | 657 | xe_irq_resume(xe); |
| 658 | 658 | ||
| 659 | for_each_gt(gt, xe, id) | 659 | for_each_gt(gt, xe, id) |
| 660 | xe_gt_resume(gt); | 660 | xe->d3cold.allowed ? xe_gt_resume(gt) : xe_gt_runtime_resume(gt); |
| 661 | 661 | ||
| 662 | xe_display_pm_runtime_resume(xe); | 662 | xe_display_pm_runtime_resume(xe); |
| 663 | 663 | ||
| @@ -425,7 +425,7 @@ static ssize_t event_attr_show(struct device *dev, · 424 unmodified lines | |||
| 425 | struct perf_pmu_events_attr *pmu_attr = | 425 | struct perf_pmu_events_attr *pmu_attr = |
| 426 | container_of(attr, struct perf_pmu_events_attr, attr); | 426 | container_of(attr, struct perf_pmu_events_attr, attr); |
| 427 | 427 | ||
| 428 | return sprintf(buf, "event=%#04llx\n", pmu_attr->id); | 428 | return sysfs_emit(buf, "event=%#04llx\n", pmu_attr->id); |
| 429 | } | 429 | } |
| 430 | 430 | ||
| 431 | #define XE_EVENT_ATTR(name_, v_, id_) \ | 431 | #define XE_EVENT_ATTR(name_, v_, id_) \ |
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include "xe_exec_queue.h" | 12 | #include "xe_exec_queue.h" |
| 13 | #include "xe_gt.h" | 13 | #include "xe_gt.h" |
| 14 | #include "xe_migrate.h" | 14 | #include "xe_migrate.h" |
| 15 | #include "xe_page_reclaim.h" | ||
| 15 | #include "xe_pt_types.h" | 16 | #include "xe_pt_types.h" |
| 16 | #include "xe_pt_walk.h" | 17 | #include "xe_pt_walk.h" |
| 17 | #include "xe_res_cursor.h" | 18 | #include "xe_res_cursor.h" |
| @@ -1535,6 +1536,9 @@ struct xe_pt_stage_unbind_walk { · 1517 unmodified lines | |||
| 1535 | /** @modified_end: Walk range start, modified like @modified_start. */ | 1536 | /** @modified_end: Walk range start, modified like @modified_start. */ |
| 1536 | u64 modified_end; | 1537 | u64 modified_end; |
| 1537 | 1538 | ||
| 1539 | /** @prl: Backing pointer to page reclaim list in pt_update_ops */ | ||
| 1540 | struct xe_page_reclaim_list *prl; | ||
| 1541 | |||
| 1538 | /* Output */ | 1542 | /* Output */ |
| 1539 | /* @wupd: Structure to track the page-table updates we're building */ | 1543 | /* @wupd: Structure to track the page-table updates we're building */ |
| 1540 | struct xe_walk_update wupd; | 1544 | struct xe_walk_update wupd; |
| @@ -1572,6 +1576,68 @@ static bool xe_pt_check_kill(u64 addr, u64 next, unsigned int level, · 31 unmodified lines | |||
| 1572 | return false; | 1576 | return false; |
| 1573 | } | 1577 | } |
| 1574 | 1578 | ||
| 1579 | /* Huge 2MB leaf lives directly in a level-1 table and has no children */ | ||
| 1580 | static bool is_2m_pte(struct xe_pt *pte) | ||
| 1581 | { | ||
| 1582 | return pte->level == 1 && !pte->base.children; | ||
| 1583 | } | ||
| 1584 | |||
| 1585 | /* page_size = 2^(reclamation_size + XE_PTE_SHIFT) */ | ||
| 1586 | #define COMPUTE_RECLAIM_ADDRESS_MASK(page_size) \ | ||
| 1587 | ({ \ | ||
| 1588 | BUILD_BUG_ON(!__builtin_constant_p(page_size)); \ | ||
| 1589 | ilog2(page_size) - XE_PTE_SHIFT; \ | ||
| 1590 | }) | ||
| 1591 | |||
| 1592 | static int generate_reclaim_entry(struct xe_tile *tile, | ||
| 1593 | struct xe_page_reclaim_list *prl, | ||
| 1594 | u64 pte, struct xe_pt *xe_child) | ||
| 1595 | { | ||
| 1596 | struct xe_guc_page_reclaim_entry *reclaim_entries = prl->entries; | ||
| 1597 | u64 phys_page = (pte & XE_PTE_ADDR_MASK) >> XE_PTE_SHIFT; | ||
| 1598 | int num_entries = prl->num_entries; | ||
| 1599 | u32 reclamation_size; | ||
| 1600 | |||
| 1601 | xe_tile_assert(tile, xe_child->level <= MAX_HUGEPTE_LEVEL); | ||
| 1602 | xe_tile_assert(tile, reclaim_entries); | ||
| 1603 | xe_tile_assert(tile, num_entries < XE_PAGE_RECLAIM_MAX_ENTRIES - 1); | ||
| 1604 | |||
| 1605 | if (!xe_page_reclaim_list_valid(prl)) | ||
| 1606 | return -EINVAL; | ||
| 1607 | |||
| 1608 | /** | ||
| 1609 | * reclamation_size indicates the size of the page to be | ||
| 1610 | * invalidated and flushed from non-coherent cache. | ||
| 1611 | * Page size is computed as 2^(reclamation_size + XE_PTE_SHIFT) bytes. | ||
| 1612 | * Only 4K, 64K (level 0), and 2M pages are supported by hardware for page reclaim | ||
| 1613 | */ | ||
| 1614 | if (xe_child->level == 0 && !(pte & XE_PTE_PS64)) { | ||
| 1615 | reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_4K); /* reclamation_size = 0 */ | ||
| 1616 | } else if (xe_child->level == 0) { | ||
| 1617 | reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_64K); /* reclamation_size = 4 */ | ||
| 1618 | } else if (is_2m_pte(xe_child)) { | ||
| 1619 | reclamation_size = COMPUTE_RECLAIM_ADDRESS_MASK(SZ_2M); /* reclamation_size = 9 */ | ||
| 1620 | } else { | ||
| 1621 | xe_page_reclaim_list_invalidate(prl); | ||
| 1622 | vm_dbg(&tile_to_xe(tile)->drm, | ||
| 1623 | "PRL invalidate: unsupported PTE level=%u pte=%#llx\n", | ||
| 1624 | xe_child->level, pte); | ||
| 1625 | return -EINVAL; | ||
| 1626 | } | ||
| 1627 | |||
| 1628 | reclaim_entries[num_entries].qw = | ||
| 1629 | FIELD_PREP(XE_PAGE_RECLAIM_VALID, 1) | | ||
| 1630 | FIELD_PREP(XE_PAGE_RECLAIM_SIZE, reclamation_size) | | ||
| 1631 | FIELD_PREP(XE_PAGE_RECLAIM_ADDR_LO, phys_page) | | ||
| 1632 | FIELD_PREP(XE_PAGE_RECLAIM_ADDR_HI, phys_page >> 20); | ||
| 1633 | prl->num_entries++; | ||
| 1634 | vm_dbg(&tile_to_xe(tile)->drm, | ||
| 1635 | "PRL add entry: level=%u pte=%#llx reclamation_size=%u prl_idx=%d\n", | ||
| 1636 | xe_child->level, pte, reclamation_size, num_entries); | ||
| 1637 | |||
| 1638 | return 0; | ||
| 1639 | } | ||
| 1640 | |||
| 1575 | static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, | 1641 | static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, |
| 1576 | unsigned int level, u64 addr, u64 next, | 1642 | unsigned int level, u64 addr, u64 next, |
| 1577 | struct xe_ptw **child, | 1643 | struct xe_ptw **child, |
| @@ -1579,11 +1645,48 @@ static int xe_pt_stage_unbind_entry(struct xe_ptw *parent, pgoff_t offset, · 1 unmodified line | |||
| 1579 | struct xe_pt_walk *walk) | 1645 | struct xe_pt_walk *walk) |
| 1580 | { | 1646 | { |
| 1581 | struct xe_pt *xe_child = container_of(*child, typeof(*xe_child), base); | 1647 | struct xe_pt *xe_child = container_of(*child, typeof(*xe_child), base); |
| 1648 | struct xe_pt_stage_unbind_walk *xe_walk = | ||
| 1649 | container_of(walk, typeof(*xe_walk), base); | ||
| 1650 | struct xe_device *xe = tile_to_xe(xe_walk->tile); | ||
| 1582 | 1651 | ||
| 1583 | XE_WARN_ON(!*child); | 1652 | XE_WARN_ON(!*child); |
| 1584 | XE_WARN_ON(!level); | 1653 | XE_WARN_ON(!level); |
| 1654 | /* Check for leaf node */ | ||
| 1655 | if (xe_walk->prl && xe_page_reclaim_list_valid(xe_walk->prl) && | ||
| 1656 | !xe_child->base.children) { | ||
| 1657 | struct iosys_map *leaf_map = &xe_child->bo->vmap; | ||
| 1658 | pgoff_t first = xe_pt_offset(addr, 0, walk); | ||
| 1659 | pgoff_t count = xe_pt_num_entries(addr, next, 0, walk); | ||
| 1660 | |||
| 1661 | for (pgoff_t i = 0; i < count; i++) { | ||
| 1662 | u64 pte = xe_map_rd(xe, leaf_map, (first + i) * sizeof(u64), u64); | ||
| 1663 | int ret; | ||
| 1664 | |||
| 1665 | /* Account for NULL terminated entry on end (-1) */ | ||
| 1666 | if (xe_walk->prl->num_entries < XE_PAGE_RECLAIM_MAX_ENTRIES - 1) { | ||
| 1667 | ret = generate_reclaim_entry(xe_walk->tile, xe_walk->prl, | ||
| 1668 | pte, xe_child); | ||
| 1669 | if (ret) | ||
| 1670 | break; | ||
| 1671 | } else { | ||
| 1672 | /* overflow, mark as invalid */ | ||
| 1673 | xe_page_reclaim_list_invalidate(xe_walk->prl); | ||
| 1674 | vm_dbg(&xe->drm, | ||
| 1675 | "PRL invalidate: overflow while adding pte=%#llx", | ||
| 1676 | pte); | ||
| 1677 | break; | ||
| 1678 | } | ||
| 1679 | } | ||
| 1680 | } | ||
| 1585 | 1681 | ||
| 1586 | xe_pt_check_kill(addr, next, level - 1, xe_child, action, walk); | 1682 | /* If aborting page walk early, invalidate PRL since PTE may be dropped from this abort */ |
| 1683 | if (xe_pt_check_kill(addr, next, level - 1, xe_child, action, walk) && | ||
| 1684 | xe_walk->prl && level > 1 && xe_child->base.children && xe_child->num_live != 0) { | ||
| 1685 | xe_page_reclaim_list_invalidate(xe_walk->prl); | ||
| 1686 | vm_dbg(&xe->drm, | ||
| 1687 | "PRL invalidate: kill at level=%u addr=%#llx next=%#llx num_live=%u\n", | ||
| 1688 | level, addr, next, xe_child->num_live); | ||
| 1689 | } | ||
| 1587 | 1690 | ||
| 1588 | return 0; | 1691 | return 0; |
| 1589 | } | 1692 | } |
| @@ -1654,6 +1757,8 @@ static unsigned int xe_pt_stage_unbind(struct xe_tile *tile, · 64 unmodified lines | |||
| 1654 | { | 1757 | { |
| 1655 | u64 start = range ? xe_svm_range_start(range) : xe_vma_start(vma); | 1758 | u64 start = range ? xe_svm_range_start(range) : xe_vma_start(vma); |
| 1656 | u64 end = range ? xe_svm_range_end(range) : xe_vma_end(vma); | 1759 | u64 end = range ? xe_svm_range_end(range) : xe_vma_end(vma); |
| 1760 | struct xe_vm_pgtable_update_op *pt_update_op = | ||
| 1761 | container_of(entries, struct xe_vm_pgtable_update_op, entries[0]); | ||
| 1657 | struct xe_pt_stage_unbind_walk xe_walk = { | 1762 | struct xe_pt_stage_unbind_walk xe_walk = { |
| 1658 | .base = { | 1763 | .base = { |
| 1659 | .ops = &xe_pt_stage_unbind_ops, | 1764 | .ops = &xe_pt_stage_unbind_ops, |
| @@ -1665,6 +1770,7 @@ static unsigned int xe_pt_stage_unbind(struct xe_tile *tile, · 5 unmodified lines | |||
| 1665 | .modified_start = start, | 1770 | .modified_start = start, |
| 1666 | .modified_end = end, | 1771 | .modified_end = end, |
| 1667 | .wupd.entries = entries, | 1772 | .wupd.entries = entries, |
| 1773 | .prl = pt_update_op->prl, | ||
| 1668 | }; | 1774 | }; |
| 1669 | struct xe_pt *pt = vm->pt_root[tile->id]; | 1775 | struct xe_pt *pt = vm->pt_root[tile->id]; |
| 1670 | 1776 | ||
| @@ -1897,6 +2003,7 @@ static int unbind_op_prepare(struct xe_tile *tile, · 226 unmodified lines | |||
| 1897 | struct xe_vm_pgtable_update_ops *pt_update_ops, | 2003 | struct xe_vm_pgtable_update_ops *pt_update_ops, |
| 1898 | struct xe_vma *vma) | 2004 | struct xe_vma *vma) |
| 1899 | { | 2005 | { |
| 2006 | struct xe_device *xe = tile_to_xe(tile); | ||
| 1900 | u32 current_op = pt_update_ops->current_op; | 2007 | u32 current_op = pt_update_ops->current_op; |
| 1901 | struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[current_op]; | 2008 | struct xe_vm_pgtable_update_op *pt_op = &pt_update_ops->ops[current_op]; |
| 1902 | int err; | 2009 | int err; |
| @@ -1914,6 +2021,17 @@ static int unbind_op_prepare(struct xe_tile *tile, · 11 unmodified lines | |||
| 1914 | pt_op->vma = vma; | 2021 | pt_op->vma = vma; |
| 1915 | pt_op->bind = false; | 2022 | pt_op->bind = false; |
| 1916 | pt_op->rebind = false; | 2023 | pt_op->rebind = false; |
| 2024 | /* | ||
| 2025 | * Maintain one PRL located in pt_update_ops that all others in unbind op reference. | ||
| 2026 | * Ensure that PRL is allocated only once, and if invalidated, remains an invalidated PRL. | ||
| 2027 | */ | ||
| 2028 | if (xe->info.has_page_reclaim_hw_assist && | ||
| 2029 | xe_page_reclaim_list_is_new(&pt_update_ops->prl)) | ||
| 2030 | xe_page_reclaim_list_alloc_entries(&pt_update_ops->prl); | ||
| 2031 | |||
| 2032 | /* Page reclaim may not be needed due to other features, so skip the corresponding VMA */ | ||
| 2033 | pt_op->prl = (xe_page_reclaim_list_valid(&pt_update_ops->prl) && | ||
| 2034 | !xe_page_reclaim_skip(tile, vma)) ? &pt_update_ops->prl : NULL; | ||
| 1917 | 2035 | ||
| 1918 | err = vma_reserve_fences(tile_to_xe(tile), vma); | 2036 | err = vma_reserve_fences(tile_to_xe(tile), vma); |
| 1919 | if (err) | 2037 | if (err) |
| @@ -1979,6 +2097,7 @@ static int unbind_range_prepare(struct xe_vm *vm, · 59 unmodified lines | |||
| 1979 | pt_op->vma = XE_INVALID_VMA; | 2097 | pt_op->vma = XE_INVALID_VMA; |
| 1980 | pt_op->bind = false; | 2098 | pt_op->bind = false; |
| 1981 | pt_op->rebind = false; | 2099 | pt_op->rebind = false; |
| 2100 | pt_op->prl = NULL; | ||
| 1982 | 2101 | ||
| 1983 | pt_op->num_entries = xe_pt_stage_unbind(tile, vm, NULL, range, | 2102 | pt_op->num_entries = xe_pt_stage_unbind(tile, vm, NULL, range, |
| 1984 | pt_op->entries); | 2103 | pt_op->entries); |
| @@ -2096,6 +2215,7 @@ xe_pt_update_ops_init(struct xe_vm_pgtable_update_ops *pt_update_ops) · 111 unmodified lines | |||
| 2096 | init_llist_head(&pt_update_ops->deferred); | 2215 | init_llist_head(&pt_update_ops->deferred); |
| 2097 | pt_update_ops->start = ~0x0ull; | 2216 | pt_update_ops->start = ~0x0ull; |
| 2098 | pt_update_ops->last = 0x0ull; | 2217 | pt_update_ops->last = 0x0ull; |
| 2218 | xe_page_reclaim_list_init(&pt_update_ops->prl); | ||
| 2099 | } | 2219 | } |
| 2100 | 2220 | ||
| 2101 | /** | 2221 | /** |
| @@ -2393,6 +2513,17 @@ xe_pt_update_ops_run(struct xe_tile *tile, struct xe_vma_ops *vops) · 291 unmodified lines | |||
| 2393 | goto kill_vm_tile1; | 2513 | goto kill_vm_tile1; |
| 2394 | } | 2514 | } |
| 2395 | update.ijob = ijob; | 2515 | update.ijob = ijob; |
| 2516 | /* | ||
| 2517 | * Only add page reclaim for the primary GT. Media GT does not have | ||
| 2518 | * any PPC to flush, so enabling the PPC flush bit for media is | ||
| 2519 | * effectively a NOP and provides no performance benefit nor | ||
| 2520 | * interfere with primary GT. | ||
| 2521 | */ | ||
| 2522 | if (xe_page_reclaim_list_valid(&pt_update_ops->prl)) { | ||
| 2523 | xe_tlb_inval_job_add_page_reclaim(ijob, &pt_update_ops->prl); | ||
| 2524 | /* Release ref from alloc, job will now handle it */ | ||
| 2525 | xe_page_reclaim_list_invalidate(&pt_update_ops->prl); | ||
| 2526 | } | ||
| 2396 | 2527 | ||
| 2397 | if (tile->media_gt) { | 2528 | if (tile->media_gt) { |
| 2398 | dep_scheduler = to_dep_scheduler(q, tile->media_gt); | 2529 | dep_scheduler = to_dep_scheduler(q, tile->media_gt); |
| @@ -2518,6 +2649,8 @@ void xe_pt_update_ops_fini(struct xe_tile *tile, struct xe_vma_ops *vops) · 119 unmodified lines | |||
| 2518 | &vops->pt_update_ops[tile->id]; | 2649 | &vops->pt_update_ops[tile->id]; |
| 2519 | int i; | 2650 | int i; |
| 2520 | 2651 | ||
| 2652 | xe_page_reclaim_entries_put(pt_update_ops->prl.entries); | ||
| 2653 | |||
| 2521 | lockdep_assert_held(&vops->vm->lock); | 2654 | lockdep_assert_held(&vops->vm->lock); |
| 2522 | xe_vm_assert_held(vops->vm); | 2655 | xe_vm_assert_held(vops->vm); |
| 2523 | 2656 | ||
| @@ -8,6 +8,7 @@ · 7 unmodified lines | |||
| 8 | 8 | ||
| 9 | #include <linux/types.h> | 9 | #include <linux/types.h> |
| 10 | 10 | ||
| 11 | #include "xe_page_reclaim.h" | ||
| 11 | #include "xe_pt_walk.h" | 12 | #include "xe_pt_walk.h" |
| 12 | 13 | ||
| 13 | struct xe_bo; | 14 | struct xe_bo; |
| @@ -79,6 +80,8 @@ struct xe_vm_pgtable_update_op { · 65 unmodified lines | |||
| 79 | struct xe_vm_pgtable_update entries[XE_VM_MAX_LEVEL * 2 + 1]; | 80 | struct xe_vm_pgtable_update entries[XE_VM_MAX_LEVEL * 2 + 1]; |
| 80 | /** @vma: VMA for operation, operation not valid if NULL */ | 81 | /** @vma: VMA for operation, operation not valid if NULL */ |
| 81 | struct xe_vma *vma; | 82 | struct xe_vma *vma; |
| 83 | /** @prl: Backing pointer to page reclaim list of pt_update_ops */ | ||
| 84 | struct xe_page_reclaim_list *prl; | ||
| 82 | /** @num_entries: number of entries for this update operation */ | 85 | /** @num_entries: number of entries for this update operation */ |
| 83 | u32 num_entries; | 86 | u32 num_entries; |
| 84 | /** @bind: is a bind */ | 87 | /** @bind: is a bind */ |
| @@ -95,6 +98,8 @@ struct xe_vm_pgtable_update_ops { · 10 unmodified lines | |||
| 95 | struct llist_head deferred; | 98 | struct llist_head deferred; |
| 96 | /** @q: exec queue for PT operations */ | 99 | /** @q: exec queue for PT operations */ |
| 97 | struct xe_exec_queue *q; | 100 | struct xe_exec_queue *q; |
| 101 | /** @prl: embedded page reclaim list */ | ||
| 102 | struct xe_page_reclaim_list prl; | ||
| 98 | /** @start: start address of ops */ | 103 | /** @start: start address of ops */ |
| 99 | u64 start; | 104 | u64 start; |
| 100 | /** @last: last address of ops */ | 105 | /** @last: last address of ops */ |
| @@ -58,10 +58,9 @@ bool xe_pxp_is_enabled(const struct xe_pxp *pxp) · 57 unmodified lines | |||
| 58 | static bool pxp_prerequisites_done(const struct xe_pxp *pxp) | 58 | static bool pxp_prerequisites_done(const struct xe_pxp *pxp) |
| 59 | { | 59 | { |
| 60 | struct xe_gt *gt = pxp->gt; | 60 | struct xe_gt *gt = pxp->gt; |
| 61 | unsigned int fw_ref; | ||
| 62 | bool ready; | 61 | bool ready; |
| 63 | 62 | ||
| 64 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | 63 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 65 | 64 | ||
| 66 | /* | 65 | /* |
| 67 | * If force_wake fails we could falsely report the prerequisites as not | 66 | * If force_wake fails we could falsely report the prerequisites as not |
| @@ -71,14 +70,12 @@ static bool pxp_prerequisites_done(const struct xe_pxp *pxp) · 3 unmodified lines | |||
| 71 | * PXP. Therefore, we can just log the force_wake error and not escalate | 70 | * PXP. Therefore, we can just log the force_wake error and not escalate |
| 72 | * it. | 71 | * it. |
| 73 | */ | 72 | */ |
| 74 | XE_WARN_ON(!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)); | 73 | XE_WARN_ON(!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)); |
| 75 | 74 | ||
| 76 | /* PXP requires both HuC authentication via GSC and GSC proxy initialized */ | 75 | /* PXP requires both HuC authentication via GSC and GSC proxy initialized */ |
| 77 | ready = xe_huc_is_authenticated(>->uc.huc, XE_HUC_AUTH_VIA_GSC) && | 76 | ready = xe_huc_is_authenticated(>->uc.huc, XE_HUC_AUTH_VIA_GSC) && |
| 78 | xe_gsc_proxy_init_done(>->uc.gsc); | 77 | xe_gsc_proxy_init_done(>->uc.gsc); |
| 79 | 78 | ||
| 80 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 81 | |||
| 82 | return ready; | 79 | return ready; |
| 83 | } | 80 | } |
| 84 | 81 | ||
| @@ -104,13 +101,12 @@ int xe_pxp_get_readiness_status(struct xe_pxp *pxp) · 19 unmodified lines | |||
| 104 | xe_uc_fw_status_to_error(pxp->gt->uc.gsc.fw.status)) | 101 | xe_uc_fw_status_to_error(pxp->gt->uc.gsc.fw.status)) |
| 105 | return -EIO; | 102 | return -EIO; |
| 106 | 103 | ||
| 107 | xe_pm_runtime_get(pxp->xe); | 104 | guard(xe_pm_runtime)(pxp->xe); |
| 108 | 105 | ||
| 109 | /* PXP requires both HuC loaded and GSC proxy initialized */ | 106 | /* PXP requires both HuC loaded and GSC proxy initialized */ |
| 110 | if (pxp_prerequisites_done(pxp)) | 107 | if (pxp_prerequisites_done(pxp)) |
| 111 | ret = 1; | 108 | ret = 1; |
| 112 | 109 | ||
| 113 | xe_pm_runtime_put(pxp->xe); | ||
| 114 | return ret; | 110 | return ret; |
| 115 | } | 111 | } |
| 116 | 112 | ||
| @@ -135,35 +131,28 @@ static void pxp_invalidate_queues(struct xe_pxp *pxp); · 18 unmodified lines | |||
| 135 | static int pxp_terminate_hw(struct xe_pxp *pxp) | 131 | static int pxp_terminate_hw(struct xe_pxp *pxp) |
| 136 | { | 132 | { |
| 137 | struct xe_gt *gt = pxp->gt; | 133 | struct xe_gt *gt = pxp->gt; |
| 138 | unsigned int fw_ref; | ||
| 139 | int ret = 0; | 134 | int ret = 0; |
| 140 | 135 | ||
| 141 | drm_dbg(&pxp->xe->drm, "Terminating PXP\n"); | 136 | drm_dbg(&pxp->xe->drm, "Terminating PXP\n"); |
| 142 | 137 | ||
| 143 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 138 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 144 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) { | 139 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT)) |
| 145 | ret = -EIO; | 140 | return -EIO; |
| 146 | goto out; | ||
| 147 | } | ||
| 148 | 141 | ||
| 149 | /* terminate the hw session */ | 142 | /* terminate the hw session */ |
| 150 | ret = xe_pxp_submit_session_termination(pxp, ARB_SESSION); | 143 | ret = xe_pxp_submit_session_termination(pxp, ARB_SESSION); |
| 151 | if (ret) | 144 | if (ret) |
| 152 | goto out; | 145 | return ret; |
| 153 | 146 | ||
| 154 | ret = pxp_wait_for_session_state(pxp, ARB_SESSION, false); | 147 | ret = pxp_wait_for_session_state(pxp, ARB_SESSION, false); |
| 155 | if (ret) | 148 | if (ret) |
| 156 | goto out; | 149 | return ret; |
| 157 | 150 | ||
| 158 | /* Trigger full HW cleanup */ | 151 | /* Trigger full HW cleanup */ |
| 159 | xe_mmio_write32(>->mmio, KCR_GLOBAL_TERMINATE, 1); | 152 | xe_mmio_write32(>->mmio, KCR_GLOBAL_TERMINATE, 1); |
| 160 | 153 | ||
| 161 | /* now we can tell the GSC to clean up its own state */ | 154 | /* now we can tell the GSC to clean up its own state */ |
| 162 | ret = xe_pxp_submit_session_invalidation(&pxp->gsc_res, ARB_SESSION); | 155 | return xe_pxp_submit_session_invalidation(&pxp->gsc_res, ARB_SESSION); |
| 163 | |||
| 164 | out: | ||
| 165 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 166 | return ret; | ||
| 167 | } | 156 | } |
| 168 | 157 | ||
| 169 | static void mark_termination_in_progress(struct xe_pxp *pxp) | 158 | static void mark_termination_in_progress(struct xe_pxp *pxp) |
| @@ -326,14 +315,12 @@ static int kcr_pxp_set_status(const struct xe_pxp *pxp, bool enable) · 156 unmodified lines | |||
| 326 | { | 315 | { |
| 327 | u32 val = enable ? _MASKED_BIT_ENABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES) : | 316 | u32 val = enable ? _MASKED_BIT_ENABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES) : |
| 328 | _MASKED_BIT_DISABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES); | 317 | _MASKED_BIT_DISABLE(KCR_INIT_ALLOW_DISPLAY_ME_WRITES); |
| 329 | unsigned int fw_ref; | ||
| 330 | 318 | ||
| 331 | fw_ref = xe_force_wake_get(gt_to_fw(pxp->gt), XE_FW_GT); | 319 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(pxp->gt), XE_FW_GT); |
| 332 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) | 320 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT)) |
| 333 | return -EIO; | 321 | return -EIO; |
| 334 | 322 | ||
| 335 | xe_mmio_write32(&pxp->gt->mmio, KCR_INIT, val); | 323 | xe_mmio_write32(&pxp->gt->mmio, KCR_INIT, val); |
| 336 | xe_force_wake_put(gt_to_fw(pxp->gt), fw_ref); | ||
| 337 | 324 | ||
| 338 | return 0; | 325 | return 0; |
| 339 | } | 326 | } |
| @@ -453,34 +440,28 @@ out: · 113 unmodified lines | |||
| 453 | static int __pxp_start_arb_session(struct xe_pxp *pxp) | 440 | static int __pxp_start_arb_session(struct xe_pxp *pxp) |
| 454 | { | 441 | { |
| 455 | int ret; | 442 | int ret; |
| 456 | unsigned int fw_ref; | ||
| 457 | 443 | ||
| 458 | fw_ref = xe_force_wake_get(gt_to_fw(pxp->gt), XE_FW_GT); | 444 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(pxp->gt), XE_FW_GT); |
| 459 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FW_GT)) | 445 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FW_GT)) |
| 460 | return -EIO; | 446 | return -EIO; |
| 461 | 447 | ||
| 462 | if (pxp_session_is_in_play(pxp, ARB_SESSION)) { | 448 | if (pxp_session_is_in_play(pxp, ARB_SESSION)) |
| 463 | ret = -EEXIST; | 449 | return -EEXIST; |
| 464 | goto out_force_wake; | ||
| 465 | } | ||
| 466 | 450 | ||
| 467 | ret = xe_pxp_submit_session_init(&pxp->gsc_res, ARB_SESSION); | 451 | ret = xe_pxp_submit_session_init(&pxp->gsc_res, ARB_SESSION); |
| 468 | if (ret) { | 452 | if (ret) { |
| 469 | drm_err(&pxp->xe->drm, "Failed to init PXP arb session: %pe\n", ERR_PTR(ret)); | 453 | drm_err(&pxp->xe->drm, "Failed to init PXP arb session: %pe\n", ERR_PTR(ret)); |
| 470 | goto out_force_wake; | 454 | return ret; |
| 471 | } | 455 | } |
| 472 | 456 | ||
| 473 | ret = pxp_wait_for_session_state(pxp, ARB_SESSION, true); | 457 | ret = pxp_wait_for_session_state(pxp, ARB_SESSION, true); |
| 474 | if (ret) { | 458 | if (ret) { |
| 475 | drm_err(&pxp->xe->drm, "PXP ARB session failed to go in play%pe\n", ERR_PTR(ret)); | 459 | drm_err(&pxp->xe->drm, "PXP ARB session failed to go in play%pe\n", ERR_PTR(ret)); |
| 476 | goto out_force_wake; | 460 | return ret; |
| 477 | } | 461 | } |
| 478 | 462 | ||
| 479 | drm_dbg(&pxp->xe->drm, "PXP ARB session is active\n"); | 463 | drm_dbg(&pxp->xe->drm, "PXP ARB session is active\n"); |
| 480 | 464 | return 0; | |
| 481 | out_force_wake: | ||
| 482 | xe_force_wake_put(gt_to_fw(pxp->gt), fw_ref); | ||
| 483 | return ret; | ||
| 484 | } | 465 | } |
| 485 | 466 | ||
| 486 | /** | 467 | /** |
| @@ -122,7 +122,6 @@ query_engine_cycles(struct xe_device *xe, · 121 unmodified lines | |||
| 122 | __ktime_func_t cpu_clock; | 122 | __ktime_func_t cpu_clock; |
| 123 | struct xe_hw_engine *hwe; | 123 | struct xe_hw_engine *hwe; |
| 124 | struct xe_gt *gt; | 124 | struct xe_gt *gt; |
| 125 | unsigned int fw_ref; | ||
| 126 | 125 | ||
| 127 | if (IS_SRIOV_VF(xe)) | 126 | if (IS_SRIOV_VF(xe)) |
| 128 | return -EOPNOTSUPP; | 127 | return -EOPNOTSUPP; |
| @@ -158,16 +157,13 @@ query_engine_cycles(struct xe_device *xe, · 29 unmodified lines | |||
| 158 | if (!hwe) | 157 | if (!hwe) |
| 159 | return -EINVAL; | 158 | return -EINVAL; |
| 160 | 159 | ||
| 161 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | 160 | xe_with_force_wake(fw_ref, gt_to_fw(gt), XE_FORCEWAKE_ALL) { |
| 162 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) { | 161 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) |
| 163 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | 162 | return -EIO; |
| 164 | return -EIO; | ||
| 165 | } | ||
| 166 | |||
| 167 | hwe_read_timestamp(hwe, &resp.engine_cycles, &resp.cpu_timestamp, | ||
| 168 | &resp.cpu_delta, cpu_clock); | ||
| 169 | 163 | ||
| 170 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | 164 | hwe_read_timestamp(hwe, &resp.engine_cycles, &resp.cpu_timestamp, |
| 165 | &resp.cpu_delta, cpu_clock); | ||
| 166 | } | ||
| 171 | 167 | ||
| 172 | if (GRAPHICS_VER(xe) >= 20) | 168 | if (GRAPHICS_VER(xe) >= 20) |
| 173 | resp.width = 64; | 169 | resp.width = 64; |
| @@ -342,6 +338,9 @@ static int query_config(struct xe_device *xe, struct drm_xe_device_query *query) · 168 unmodified lines | |||
| 342 | if (xe->info.has_usm && IS_ENABLED(CONFIG_DRM_XE_GPUSVM)) | 338 | if (xe->info.has_usm && IS_ENABLED(CONFIG_DRM_XE_GPUSVM)) |
| 343 | config->info[DRM_XE_QUERY_CONFIG_FLAGS] |= | 339 | config->info[DRM_XE_QUERY_CONFIG_FLAGS] |= |
| 344 | DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR; | 340 | DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR; |
| 341 | if (GRAPHICS_VER(xe) >= 20) | ||
| 342 | config->info[DRM_XE_QUERY_CONFIG_FLAGS] |= | ||
| 343 | DRM_XE_QUERY_CONFIG_FLAG_HAS_NO_COMPRESSION_HINT; | ||
| 345 | config->info[DRM_XE_QUERY_CONFIG_FLAGS] |= | 344 | config->info[DRM_XE_QUERY_CONFIG_FLAGS] |= |
| 346 | DRM_XE_QUERY_CONFIG_FLAG_HAS_LOW_LATENCY; | 345 | DRM_XE_QUERY_CONFIG_FLAG_HAS_LOW_LATENCY; |
| 347 | config->info[DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT] = | 346 | config->info[DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT] = |
| @@ -686,7 +685,9 @@ static int query_oa_units(struct xe_device *xe, · 338 unmodified lines | |||
| 686 | du->capabilities = DRM_XE_OA_CAPS_BASE | DRM_XE_OA_CAPS_SYNCS | | 685 | du->capabilities = DRM_XE_OA_CAPS_BASE | DRM_XE_OA_CAPS_SYNCS | |
| 687 | DRM_XE_OA_CAPS_OA_BUFFER_SIZE | | 686 | DRM_XE_OA_CAPS_OA_BUFFER_SIZE | |
| 688 | DRM_XE_OA_CAPS_WAIT_NUM_REPORTS | | 687 | DRM_XE_OA_CAPS_WAIT_NUM_REPORTS | |
| 689 | DRM_XE_OA_CAPS_OAM; | 688 | DRM_XE_OA_CAPS_OAM | |
| 689 | DRM_XE_OA_CAPS_OA_UNIT_GT_ID; | ||
| 690 | du->gt_id = u->gt->info.id; | ||
| 690 | j = 0; | 691 | j = 0; |
| 691 | for_each_hw_engine(hwe, gt, hwe_id) { | 692 | for_each_hw_engine(hwe, gt, hwe_id) { |
| 692 | if (!xe_hw_engine_is_reserved(hwe) && | 693 | if (!xe_hw_engine_is_reserved(hwe) && |
| @@ -168,7 +168,6 @@ void xe_reg_sr_apply_mmio(struct xe_reg_sr *sr, struct xe_gt *gt) · 167 unmodified lines | |||
| 168 | { | 168 | { |
| 169 | struct xe_reg_sr_entry *entry; | 169 | struct xe_reg_sr_entry *entry; |
| 170 | unsigned long reg; | 170 | unsigned long reg; |
| 171 | unsigned int fw_ref; | ||
| 172 | 171 | ||
| 173 | if (xa_empty(&sr->xa)) | 172 | if (xa_empty(&sr->xa)) |
| 174 | return; | 173 | return; |
| @@ -178,20 +177,14 @@ void xe_reg_sr_apply_mmio(struct xe_reg_sr *sr, struct xe_gt *gt) · 3 unmodified lines | |||
| 178 | 177 | ||
| 179 | xe_gt_dbg(gt, "Applying %s save-restore MMIOs\n", sr->name); | 178 | xe_gt_dbg(gt, "Applying %s save-restore MMIOs\n", sr->name); |
| 180 | 179 | ||
| 181 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FORCEWAKE_ALL); | 180 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FORCEWAKE_ALL); |
| 182 | if (!xe_force_wake_ref_has_domain(fw_ref, XE_FORCEWAKE_ALL)) | 181 | if (!xe_force_wake_ref_has_domain(fw_ref.domains, XE_FORCEWAKE_ALL)) { |
| 183 | goto err_force_wake; | 182 | xe_gt_err(gt, "Failed to apply, err=-ETIMEDOUT\n"); |
| 183 | return; | ||
| 184 | } | ||
| 184 | 185 | ||
| 185 | xa_for_each(&sr->xa, reg, entry) | 186 | xa_for_each(&sr->xa, reg, entry) |
| 186 | apply_one_mmio(gt, entry); | 187 | apply_one_mmio(gt, entry); |
| 187 | |||
| 188 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 189 | |||
| 190 | return; | ||
| 191 | |||
| 192 | err_force_wake: | ||
| 193 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 194 | xe_gt_err(gt, "Failed to apply, err=-ETIMEDOUT\n"); | ||
| 195 | } | 188 | } |
| 196 | 189 | ||
| 197 | /** | 190 | /** |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include "regs/xe_gt_regs.h" | 9 | #include "regs/xe_gt_regs.h" |
| 10 | #include "regs/xe_oa_regs.h" | 10 | #include "regs/xe_oa_regs.h" |
| 11 | #include "regs/xe_regs.h" | 11 | #include "regs/xe_regs.h" |
| 12 | #include "xe_device.h" | ||
| 12 | #include "xe_gt_types.h" | 13 | #include "xe_gt_types.h" |
| 13 | #include "xe_gt_printk.h" | 14 | #include "xe_gt_printk.h" |
| 14 | #include "xe_platform_types.h" | 15 | #include "xe_platform_types.h" |
| @@ -26,6 +27,13 @@ static bool match_not_render(const struct xe_device *xe, · 11 unmodified lines | |||
| 26 | return hwe->class != XE_ENGINE_CLASS_RENDER; | 27 | return hwe->class != XE_ENGINE_CLASS_RENDER; |
| 27 | } | 28 | } |
| 28 | 29 | ||
| 30 | static bool match_has_mert(const struct xe_device *xe, | ||
| 31 | const struct xe_gt *gt, | ||
| 32 | const struct xe_hw_engine *hwe) | ||
| 33 | { | ||
| 34 | return xe_device_has_mert((struct xe_device *)xe); | ||
| 35 | } | ||
| 36 | |||
| 29 | static const struct xe_rtp_entry_sr register_whitelist[] = { | 37 | static const struct xe_rtp_entry_sr register_whitelist[] = { |
| 30 | { XE_RTP_NAME("WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865"), | 38 | { XE_RTP_NAME("WaAllowPMDepthAndInvocationCountAccessFromUMD, 1408556865"), |
| 31 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)), | 39 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, 1210), ENGINE_CLASS(RENDER)), |
| @@ -67,28 +75,6 @@ static const struct xe_rtp_entry_sr register_whitelist[] = { · 35 unmodified lines | |||
| 67 | ENGINE_CLASS(RENDER)), | 75 | ENGINE_CLASS(RENDER)), |
| 68 | XE_RTP_ACTIONS(WHITELIST(CSBE_DEBUG_STATUS(RENDER_RING_BASE), 0)) | 76 | XE_RTP_ACTIONS(WHITELIST(CSBE_DEBUG_STATUS(RENDER_RING_BASE), 0)) |
| 69 | }, | 77 | }, |
| 70 | { XE_RTP_NAME("oa_reg_render"), | ||
| 71 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, XE_RTP_END_VERSION_UNDEFINED), | ||
| 72 | ENGINE_CLASS(RENDER)), | ||
| 73 | XE_RTP_ACTIONS(WHITELIST(OAG_MMIOTRIGGER, | ||
| 74 | RING_FORCE_TO_NONPRIV_ACCESS_RW), | ||
| 75 | WHITELIST(OAG_OASTATUS, | ||
| 76 | RING_FORCE_TO_NONPRIV_ACCESS_RD), | ||
| 77 | WHITELIST(OAG_OAHEADPTR, | ||
| 78 | RING_FORCE_TO_NONPRIV_ACCESS_RD | | ||
| 79 | RING_FORCE_TO_NONPRIV_RANGE_4)) | ||
| 80 | }, | ||
| 81 | { XE_RTP_NAME("oa_reg_compute"), | ||
| 82 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, XE_RTP_END_VERSION_UNDEFINED), | ||
| 83 | ENGINE_CLASS(COMPUTE)), | ||
| 84 | XE_RTP_ACTIONS(WHITELIST(OAG_MMIOTRIGGER, | ||
| 85 | RING_FORCE_TO_NONPRIV_ACCESS_RW), | ||
| 86 | WHITELIST(OAG_OASTATUS, | ||
| 87 | RING_FORCE_TO_NONPRIV_ACCESS_RD), | ||
| 88 | WHITELIST(OAG_OAHEADPTR, | ||
| 89 | RING_FORCE_TO_NONPRIV_ACCESS_RD | | ||
| 90 | RING_FORCE_TO_NONPRIV_RANGE_4)) | ||
| 91 | }, | ||
| 92 | { XE_RTP_NAME("14024997852"), | 78 | { XE_RTP_NAME("14024997852"), |
| 93 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3005), ENGINE_CLASS(RENDER)), | 79 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3005), ENGINE_CLASS(RENDER)), |
| 94 | XE_RTP_ACTIONS(WHITELIST(FF_MODE, | 80 | XE_RTP_ACTIONS(WHITELIST(FF_MODE, |
| @@ -96,6 +82,57 @@ static const struct xe_rtp_entry_sr register_whitelist[] = { · 1 unmodified line | |||
| 96 | WHITELIST(VFLSKPD, | 82 | WHITELIST(VFLSKPD, |
| 97 | RING_FORCE_TO_NONPRIV_ACCESS_RW)) | 83 | RING_FORCE_TO_NONPRIV_ACCESS_RW)) |
| 98 | }, | 84 | }, |
| 85 | |||
| 86 | #define WHITELIST_OA_MMIO_TRG(trg, status, head) \ | ||
| 87 | WHITELIST(trg, RING_FORCE_TO_NONPRIV_ACCESS_RW), \ | ||
| 88 | WHITELIST(status, RING_FORCE_TO_NONPRIV_ACCESS_RD), \ | ||
| 89 | WHITELIST(head, RING_FORCE_TO_NONPRIV_ACCESS_RD | RING_FORCE_TO_NONPRIV_RANGE_4) | ||
| 90 | |||
| 91 | #define WHITELIST_OAG_MMIO_TRG \ | ||
| 92 | WHITELIST_OA_MMIO_TRG(OAG_MMIOTRIGGER, OAG_OASTATUS, OAG_OAHEADPTR) | ||
| 93 | |||
| 94 | #define WHITELIST_OAM_MMIO_TRG \ | ||
| 95 | WHITELIST_OA_MMIO_TRG(OAM_MMIO_TRG(XE_OAM_SAG_BASE_ADJ), \ | ||
| 96 | OAM_STATUS(XE_OAM_SAG_BASE_ADJ), \ | ||
| 97 | OAM_HEAD_POINTER(XE_OAM_SAG_BASE_ADJ)), \ | ||
| 98 | WHITELIST_OA_MMIO_TRG(OAM_MMIO_TRG(XE_OAM_SCMI_0_BASE_ADJ), \ | ||
| 99 | OAM_STATUS(XE_OAM_SCMI_0_BASE_ADJ), \ | ||
| 100 | OAM_HEAD_POINTER(XE_OAM_SCMI_0_BASE_ADJ)), \ | ||
| 101 | WHITELIST_OA_MMIO_TRG(OAM_MMIO_TRG(XE_OAM_SCMI_1_BASE_ADJ), \ | ||
| 102 | OAM_STATUS(XE_OAM_SCMI_1_BASE_ADJ), \ | ||
| 103 | OAM_HEAD_POINTER(XE_OAM_SCMI_1_BASE_ADJ)) | ||
| 104 | |||
| 105 | #define WHITELIST_OA_MERT_MMIO_TRG \ | ||
| 106 | WHITELIST_OA_MMIO_TRG(OAMERT_MMIO_TRG, OAMERT_STATUS, OAMERT_HEAD_POINTER) | ||
| 107 | |||
| 108 | { XE_RTP_NAME("oag_mmio_trg_rcs"), | ||
| 109 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, XE_RTP_END_VERSION_UNDEFINED), | ||
| 110 | ENGINE_CLASS(RENDER)), | ||
| 111 | XE_RTP_ACTIONS(WHITELIST_OAG_MMIO_TRG) | ||
| 112 | }, | ||
| 113 | { XE_RTP_NAME("oag_mmio_trg_ccs"), | ||
| 114 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(1200, XE_RTP_END_VERSION_UNDEFINED), | ||
| 115 | ENGINE_CLASS(COMPUTE)), | ||
| 116 | XE_RTP_ACTIONS(WHITELIST_OAG_MMIO_TRG) | ||
| 117 | }, | ||
| 118 | { XE_RTP_NAME("oam_mmio_trg_vcs"), | ||
| 119 | XE_RTP_RULES(MEDIA_VERSION_RANGE(1300, XE_RTP_END_VERSION_UNDEFINED), | ||
| 120 | ENGINE_CLASS(VIDEO_DECODE)), | ||
| 121 | XE_RTP_ACTIONS(WHITELIST_OAM_MMIO_TRG) | ||
| 122 | }, | ||
| 123 | { XE_RTP_NAME("oam_mmio_trg_vecs"), | ||
| 124 | XE_RTP_RULES(MEDIA_VERSION_RANGE(1300, XE_RTP_END_VERSION_UNDEFINED), | ||
| 125 | ENGINE_CLASS(VIDEO_ENHANCE)), | ||
| 126 | XE_RTP_ACTIONS(WHITELIST_OAM_MMIO_TRG) | ||
| 127 | }, | ||
| 128 | { XE_RTP_NAME("oa_mert_mmio_trg_ccs"), | ||
| 129 | XE_RTP_RULES(FUNC(match_has_mert), ENGINE_CLASS(COMPUTE)), | ||
| 130 | XE_RTP_ACTIONS(WHITELIST_OA_MERT_MMIO_TRG) | ||
| 131 | }, | ||
| 132 | { XE_RTP_NAME("oa_mert_mmio_trg_bcs"), | ||
| 133 | XE_RTP_RULES(FUNC(match_has_mert), ENGINE_CLASS(COPY)), | ||
| 134 | XE_RTP_ACTIONS(WHITELIST_OA_MERT_MMIO_TRG) | ||
| 135 | }, | ||
| 99 | }; | 136 | }; |
| 100 | 137 | ||
| 101 | static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) | 138 | static void whitelist_apply_to_hwe(struct xe_hw_engine *hwe) |
| @@ -12,7 +12,7 @@ · 11 unmodified lines | |||
| 12 | #include "regs/xe_engine_regs.h" | 12 | #include "regs/xe_engine_regs.h" |
| 13 | #include "regs/xe_gt_regs.h" | 13 | #include "regs/xe_gt_regs.h" |
| 14 | #include "regs/xe_lrc_layout.h" | 14 | #include "regs/xe_lrc_layout.h" |
| 15 | #include "xe_exec_queue_types.h" | 15 | #include "xe_exec_queue.h" |
| 16 | #include "xe_gt.h" | 16 | #include "xe_gt.h" |
| 17 | #include "xe_lrc.h" | 17 | #include "xe_lrc.h" |
| 18 | #include "xe_macros.h" | 18 | #include "xe_macros.h" |
| @@ -135,12 +135,11 @@ emit_pipe_control(u32 *dw, int i, u32 bit_group_0, u32 bit_group_1, u32 offset, · 116 unmodified lines | |||
| 135 | return i; | 135 | return i; |
| 136 | } | 136 | } |
| 137 | 137 | ||
| 138 | static int emit_pipe_invalidate(u32 mask_flags, bool invalidate_tlb, u32 *dw, | 138 | static int emit_pipe_invalidate(struct xe_exec_queue *q, u32 mask_flags, |
| 139 | int i) | 139 | bool invalidate_tlb, u32 *dw, int i) |
| 140 | { | 140 | { |
| 141 | u32 flags0 = 0; | 141 | u32 flags0 = 0; |
| 142 | u32 flags1 = PIPE_CONTROL_CS_STALL | | 142 | u32 flags1 = PIPE_CONTROL_COMMAND_CACHE_INVALIDATE | |
| 143 | PIPE_CONTROL_COMMAND_CACHE_INVALIDATE | | ||
| 144 | PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE | | 143 | PIPE_CONTROL_INSTRUCTION_CACHE_INVALIDATE | |
| 145 | PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | | 144 | PIPE_CONTROL_TEXTURE_CACHE_INVALIDATE | |
| 146 | PIPE_CONTROL_VF_CACHE_INVALIDATE | | 145 | PIPE_CONTROL_VF_CACHE_INVALIDATE | |
| @@ -152,6 +151,11 @@ static int emit_pipe_invalidate(u32 mask_flags, bool invalidate_tlb, u32 *dw, · 5 unmodified lines | |||
| 152 | if (invalidate_tlb) | 151 | if (invalidate_tlb) |
| 153 | flags1 |= PIPE_CONTROL_TLB_INVALIDATE; | 152 | flags1 |= PIPE_CONTROL_TLB_INVALIDATE; |
| 154 | 153 | ||
| 154 | if (xe_exec_queue_is_multi_queue(q)) | ||
| 155 | flags0 |= PIPE_CONTROL0_QUEUE_DRAIN_MODE; | ||
| 156 | else | ||
| 157 | flags1 |= PIPE_CONTROL_CS_STALL; | ||
| 158 | |||
| 155 | flags1 &= ~mask_flags; | 159 | flags1 &= ~mask_flags; |
| 156 | 160 | ||
| 157 | if (flags1 & PIPE_CONTROL_VF_CACHE_INVALIDATE) | 161 | if (flags1 & PIPE_CONTROL_VF_CACHE_INVALIDATE) |
| @@ -175,54 +179,52 @@ static int emit_store_imm_ppgtt_posted(u64 addr, u64 value, · 17 unmodified lines | |||
| 175 | 179 | ||
| 176 | static int emit_render_cache_flush(struct xe_sched_job *job, u32 *dw, int i) | 180 | static int emit_render_cache_flush(struct xe_sched_job *job, u32 *dw, int i) |
| 177 | { | 181 | { |
| 178 | struct xe_gt *gt = job->q->gt; | 182 | struct xe_exec_queue *q = job->q; |
| 183 | struct xe_gt *gt = q->gt; | ||
| 179 | bool lacks_render = !(gt->info.engine_mask & XE_HW_ENGINE_RCS_MASK); | 184 | bool lacks_render = !(gt->info.engine_mask & XE_HW_ENGINE_RCS_MASK); |
| 180 | u32 flags; | 185 | u32 flags0, flags1; |
| 181 | 186 | ||
| 182 | if (XE_GT_WA(gt, 14016712196)) | 187 | if (XE_GT_WA(gt, 14016712196)) |
| 183 | i = emit_pipe_control(dw, i, 0, PIPE_CONTROL_DEPTH_CACHE_FLUSH, | 188 | i = emit_pipe_control(dw, i, 0, PIPE_CONTROL_DEPTH_CACHE_FLUSH, |
| 184 | LRC_PPHWSP_FLUSH_INVAL_SCRATCH_ADDR, 0); | 189 | LRC_PPHWSP_FLUSH_INVAL_SCRATCH_ADDR, 0); |
| 185 | 190 | ||
| 186 | flags = (PIPE_CONTROL_CS_STALL | | 191 | flags0 = PIPE_CONTROL0_HDC_PIPELINE_FLUSH; |
| 187 | PIPE_CONTROL_TILE_CACHE_FLUSH | | 192 | flags1 = (PIPE_CONTROL_TILE_CACHE_FLUSH | |
| 188 | PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | | 193 | PIPE_CONTROL_RENDER_TARGET_CACHE_FLUSH | |
| 189 | PIPE_CONTROL_DEPTH_CACHE_FLUSH | | 194 | PIPE_CONTROL_DEPTH_CACHE_FLUSH | |
| 190 | PIPE_CONTROL_DC_FLUSH_ENABLE | | 195 | PIPE_CONTROL_DC_FLUSH_ENABLE | |
| 191 | PIPE_CONTROL_FLUSH_ENABLE); | 196 | PIPE_CONTROL_FLUSH_ENABLE); |
| 192 | 197 | ||
| 193 | if (XE_GT_WA(gt, 1409600907)) | 198 | if (XE_GT_WA(gt, 1409600907)) |
| 194 | flags |= PIPE_CONTROL_DEPTH_STALL; | 199 | flags1 |= PIPE_CONTROL_DEPTH_STALL; |
| 195 | 200 | ||
| 196 | if (lacks_render) | 201 | if (lacks_render) |
| 197 | flags &= ~PIPE_CONTROL_3D_ARCH_FLAGS; | 202 | flags1 &= ~PIPE_CONTROL_3D_ARCH_FLAGS; |
| 198 | else if (job->q->class == XE_ENGINE_CLASS_COMPUTE) | 203 | else if (job->q->class == XE_ENGINE_CLASS_COMPUTE) |
| 199 | flags &= ~PIPE_CONTROL_3D_ENGINE_FLAGS; | 204 | flags1 &= ~PIPE_CONTROL_3D_ENGINE_FLAGS; |
| 200 | 205 | ||
| 201 | return emit_pipe_control(dw, i, PIPE_CONTROL0_HDC_PIPELINE_FLUSH, flags, 0, 0); | 206 | if (xe_exec_queue_is_multi_queue(q)) |
| 202 | } | 207 | flags0 |= PIPE_CONTROL0_QUEUE_DRAIN_MODE; |
| 203 | 208 | else | |
| 204 | static int emit_pipe_control_to_ring_end(struct xe_hw_engine *hwe, u32 *dw, int i) | 209 | flags1 |= PIPE_CONTROL_CS_STALL; |
| 205 | { | ||
| 206 | if (hwe->class != XE_ENGINE_CLASS_RENDER) | ||
| 207 | return i; | ||
| 208 | 210 | ||
| 209 | if (XE_GT_WA(hwe->gt, 16020292621)) | 211 | return emit_pipe_control(dw, i, flags0, flags1, 0, 0); |
| 210 | i = emit_pipe_control(dw, i, 0, PIPE_CONTROL_LRI_POST_SYNC, | ||
| 211 | RING_NOPID(hwe->mmio_base).addr, 0); | ||
| 212 | |||
| 213 | return i; | ||
| 214 | } | 212 | } |
| 215 | 213 | ||
| 216 | static int emit_pipe_imm_ggtt(u32 addr, u32 value, bool stall_only, u32 *dw, | 214 | static int emit_pipe_imm_ggtt(struct xe_exec_queue *q, u32 addr, u32 value, |
| 217 | int i) | 215 | bool stall_only, u32 *dw, int i) |
| 218 | { | 216 | { |
| 219 | u32 flags = PIPE_CONTROL_CS_STALL | PIPE_CONTROL_GLOBAL_GTT_IVB | | 217 | u32 flags0 = 0, flags1 = PIPE_CONTROL_GLOBAL_GTT_IVB | PIPE_CONTROL_QW_WRITE; |
| 220 | PIPE_CONTROL_QW_WRITE; | ||
| 221 | 218 | ||
| 222 | if (!stall_only) | 219 | if (!stall_only) |
| 223 | flags |= PIPE_CONTROL_FLUSH_ENABLE; | 220 | flags1 |= PIPE_CONTROL_FLUSH_ENABLE; |
| 224 | 221 | ||
| 225 | return emit_pipe_control(dw, i, 0, flags, addr, value); | 222 | if (xe_exec_queue_is_multi_queue(q)) |
| 223 | flags0 |= PIPE_CONTROL0_QUEUE_DRAIN_MODE; | ||
| 224 | else | ||
| 225 | flags1 |= PIPE_CONTROL_CS_STALL; | ||
| 226 | |||
| 227 | return emit_pipe_control(dw, i, flags0, flags1, addr, value); | ||
| 226 | } | 228 | } |
| 227 | 229 | ||
| 228 | static u32 get_ppgtt_flag(struct xe_sched_job *job) | 230 | static u32 get_ppgtt_flag(struct xe_sched_job *job) |
| @@ -371,7 +373,7 @@ static void __emit_job_gen12_render_compute(struct xe_sched_job *job, · 142 unmodified lines | |||
| 371 | mask_flags = PIPE_CONTROL_3D_ENGINE_FLAGS; | 373 | mask_flags = PIPE_CONTROL_3D_ENGINE_FLAGS; |
| 372 | 374 | ||
| 373 | /* See __xe_pt_bind_vma() for a discussion on TLB invalidations. */ | 375 | /* See __xe_pt_bind_vma() for a discussion on TLB invalidations. */ |
| 374 | i = emit_pipe_invalidate(mask_flags, job->ring_ops_flush_tlb, dw, i); | 376 | i = emit_pipe_invalidate(job->q, mask_flags, job->ring_ops_flush_tlb, dw, i); |
| 375 | 377 | ||
| 376 | /* hsdes: 1809175790 */ | 378 | /* hsdes: 1809175790 */ |
| 377 | if (has_aux_ccs(xe)) | 379 | if (has_aux_ccs(xe)) |
| @@ -391,12 +393,10 @@ static void __emit_job_gen12_render_compute(struct xe_sched_job *job, · 13 unmodified lines | |||
| 391 | job->user_fence.value, | 393 | job->user_fence.value, |
| 392 | dw, i); | 394 | dw, i); |
| 393 | 395 | ||
| 394 | i = emit_pipe_imm_ggtt(xe_lrc_seqno_ggtt_addr(lrc), seqno, lacks_render, dw, i); | 396 | i = emit_pipe_imm_ggtt(job->q, xe_lrc_seqno_ggtt_addr(lrc), seqno, lacks_render, dw, i); |
| 395 | 397 | ||
| 396 | i = emit_user_interrupt(dw, i); | 398 | i = emit_user_interrupt(dw, i); |
| 397 | 399 | ||
| 398 | i = emit_pipe_control_to_ring_end(job->q->hwe, dw, i); | ||
| 399 | |||
| 400 | xe_gt_assert(gt, i <= MAX_JOB_SIZE_DW); | 400 | xe_gt_assert(gt, i <= MAX_JOB_SIZE_DW); |
| 401 | 401 | ||
| 402 | xe_lrc_write_ring(lrc, dw, i * sizeof(*dw)); | 402 | xe_lrc_write_ring(lrc, dw, i * sizeof(*dw)); |
| @@ -29,6 +29,7 @@ static void xe_sa_bo_manager_fini(struct drm_device *drm, void *arg) · 28 unmodified lines | |||
| 29 | kvfree(sa_manager->cpu_ptr); | 29 | kvfree(sa_manager->cpu_ptr); |
| 30 | 30 | ||
| 31 | sa_manager->bo = NULL; | 31 | sa_manager->bo = NULL; |
| 32 | sa_manager->shadow = NULL; | ||
| 32 | } | 33 | } |
| 33 | 34 | ||
| 34 | /** | 35 | /** |
| @@ -37,12 +38,14 @@ static void xe_sa_bo_manager_fini(struct drm_device *drm, void *arg) · 2 unmodified lines | |||
| 37 | * @size: number of bytes to allocate | 38 | * @size: number of bytes to allocate |
| 38 | * @guard: number of bytes to exclude from suballocations | 39 | * @guard: number of bytes to exclude from suballocations |
| 39 | * @align: alignment for each suballocated chunk | 40 | * @align: alignment for each suballocated chunk |
| 41 | * @flags: flags for suballocator | ||
| 40 | * | 42 | * |
| 41 | * Prepares the suballocation manager for suballocations. | 43 | * Prepares the suballocation manager for suballocations. |
| 42 | * | 44 | * |
| 43 | * Return: a pointer to the &xe_sa_manager or an ERR_PTR on failure. | 45 | * Return: a pointer to the &xe_sa_manager or an ERR_PTR on failure. |
| 44 | */ | 46 | */ |
| 45 | struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 guard, u32 align) | 47 | struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, |
| 48 | u32 guard, u32 align, u32 flags) | ||
| 46 | { | 49 | { |
| 47 | struct xe_device *xe = tile_to_xe(tile); | 50 | struct xe_device *xe = tile_to_xe(tile); |
| 48 | struct xe_sa_manager *sa_manager; | 51 | struct xe_sa_manager *sa_manager; |
| @@ -79,6 +82,26 @@ struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u3 · 30 unmodified lines | |||
| 79 | memset(sa_manager->cpu_ptr, 0, bo->ttm.base.size); | 82 | memset(sa_manager->cpu_ptr, 0, bo->ttm.base.size); |
| 80 | } | 83 | } |
| 81 | 84 | ||
| 85 | if (flags & XE_SA_BO_MANAGER_FLAG_SHADOW) { | ||
| 86 | struct xe_bo *shadow; | ||
| 87 | |||
| 88 | ret = drmm_mutex_init(&xe->drm, &sa_manager->swap_guard); | ||
| 89 | if (ret) | ||
| 90 | return ERR_PTR(ret); | ||
| 91 | |||
| 92 | shadow = xe_managed_bo_create_pin_map(xe, tile, size, | ||
| 93 | XE_BO_FLAG_VRAM_IF_DGFX(tile) | | ||
| 94 | XE_BO_FLAG_GGTT | | ||
| 95 | XE_BO_FLAG_GGTT_INVALIDATE | | ||
| 96 | XE_BO_FLAG_PINNED_NORESTORE); | ||
| 97 | if (IS_ERR(shadow)) { | ||
| 98 | drm_err(&xe->drm, "Failed to prepare %uKiB BO for SA manager (%pe)\n", | ||
| 99 | size / SZ_1K, shadow); | ||
| 100 | return ERR_CAST(shadow); | ||
| 101 | } | ||
| 102 | sa_manager->shadow = shadow; | ||
| 103 | } | ||
| 104 | |||
| 82 | drm_suballoc_manager_init(&sa_manager->base, managed_size, align); | 105 | drm_suballoc_manager_init(&sa_manager->base, managed_size, align); |
| 83 | ret = drmm_add_action_or_reset(&xe->drm, xe_sa_bo_manager_fini, | 106 | ret = drmm_add_action_or_reset(&xe->drm, xe_sa_bo_manager_fini, |
| 84 | sa_manager); | 107 | sa_manager); |
| @@ -88,6 +111,48 @@ struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u3 · 3 unmodified lines | |||
| 88 | return sa_manager; | 111 | return sa_manager; |
| 89 | } | 112 | } |
| 90 | 113 | ||
| 114 | /** | ||
| 115 | * xe_sa_bo_swap_shadow() - Swap the SA BO with shadow BO. | ||
| 116 | * @sa_manager: the XE sub allocator manager | ||
| 117 | * | ||
| 118 | * Swaps the sub-allocator primary buffer object with shadow buffer object. | ||
| 119 | * | ||
| 120 | * Return: None. | ||
| 121 | */ | ||
| 122 | void xe_sa_bo_swap_shadow(struct xe_sa_manager *sa_manager) | ||
| 123 | { | ||
| 124 | struct xe_device *xe = tile_to_xe(sa_manager->bo->tile); | ||
| 125 | |||
| 126 | xe_assert(xe, sa_manager->shadow); | ||
| 127 | lockdep_assert_held(&sa_manager->swap_guard); | ||
| 128 | |||
| 129 | swap(sa_manager->bo, sa_manager->shadow); | ||
| 130 | if (!sa_manager->bo->vmap.is_iomem) | ||
| 131 | sa_manager->cpu_ptr = sa_manager->bo->vmap.vaddr; | ||
| 132 | } | ||
| 133 | |||
| 134 | /** | ||
| 135 | * xe_sa_bo_sync_shadow() - Sync the SA Shadow BO with primary BO. | ||
| 136 | * @sa_bo: the sub-allocator buffer object. | ||
| 137 | * | ||
| 138 | * Synchronize sub-allocator shadow buffer object with primary buffer object. | ||
| 139 | * | ||
| 140 | * Return: None. | ||
| 141 | */ | ||
| 142 | void xe_sa_bo_sync_shadow(struct drm_suballoc *sa_bo) | ||
| 143 | { | ||
| 144 | struct xe_sa_manager *sa_manager = to_xe_sa_manager(sa_bo->manager); | ||
| 145 | struct xe_device *xe = tile_to_xe(sa_manager->bo->tile); | ||
| 146 | |||
| 147 | xe_assert(xe, sa_manager->shadow); | ||
| 148 | lockdep_assert_held(&sa_manager->swap_guard); | ||
| 149 | |||
| 150 | xe_map_memcpy_to(xe, &sa_manager->shadow->vmap, | ||
| 151 | drm_suballoc_soffset(sa_bo), | ||
| 152 | xe_sa_bo_cpu_addr(sa_bo), | ||
| 153 | drm_suballoc_size(sa_bo)); | ||
| 154 | } | ||
| 155 | |||
| 91 | /** | 156 | /** |
| 92 | * __xe_sa_bo_new() - Make a suballocation but use custom gfp flags. | 157 | * __xe_sa_bo_new() - Make a suballocation but use custom gfp flags. |
| 93 | * @sa_manager: the &xe_sa_manager | 158 | * @sa_manager: the &xe_sa_manager |
| @@ -14,12 +14,14 @@ · 13 unmodified lines | |||
| 14 | struct dma_fence; | 14 | struct dma_fence; |
| 15 | struct xe_tile; | 15 | struct xe_tile; |
| 16 | 16 | ||
| 17 | struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 guard, u32 align); | 17 | #define XE_SA_BO_MANAGER_FLAG_SHADOW BIT(0) |
| 18 | struct xe_sa_manager *__xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, | ||
| 19 | u32 guard, u32 align, u32 flags); | ||
| 18 | struct drm_suballoc *__xe_sa_bo_new(struct xe_sa_manager *sa_manager, u32 size, gfp_t gfp); | 20 | struct drm_suballoc *__xe_sa_bo_new(struct xe_sa_manager *sa_manager, u32 size, gfp_t gfp); |
| 19 | 21 | ||
| 20 | static inline struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 align) | 22 | static inline struct xe_sa_manager *xe_sa_bo_manager_init(struct xe_tile *tile, u32 size, u32 align) |
| 21 | { | 23 | { |
| 22 | return __xe_sa_bo_manager_init(tile, size, SZ_4K, align); | 24 | return __xe_sa_bo_manager_init(tile, size, SZ_4K, align, 0); |
| 23 | } | 25 | } |
| 24 | 26 | ||
| 25 | /** | 27 | /** |
| @@ -69,4 +71,18 @@ static inline void *xe_sa_bo_cpu_addr(struct drm_suballoc *sa) · 43 unmodified lines | |||
| 69 | drm_suballoc_soffset(sa); | 71 | drm_suballoc_soffset(sa); |
| 70 | } | 72 | } |
| 71 | 73 | ||
| 74 | void xe_sa_bo_swap_shadow(struct xe_sa_manager *sa_manager); | ||
| 75 | void xe_sa_bo_sync_shadow(struct drm_suballoc *sa_bo); | ||
| 76 | |||
| 77 | /** | ||
| 78 | * xe_sa_bo_swap_guard() - Retrieve the SA BO swap guard within sub-allocator. | ||
| 79 | * @sa_manager: the &xe_sa_manager | ||
| 80 | * | ||
| 81 | * Return: Sub alloctor swap guard mutex. | ||
| 82 | */ | ||
| 83 | static inline struct mutex *xe_sa_bo_swap_guard(struct xe_sa_manager *sa_manager) | ||
| 84 | { | ||
| 85 | return &sa_manager->swap_guard; | ||
| 86 | } | ||
| 87 | |||
| 72 | #endif | 88 | #endif |
| @@ -12,6 +12,9 @@ struct xe_bo; · 11 unmodified lines | |||
| 12 | struct xe_sa_manager { | 12 | struct xe_sa_manager { |
| 13 | struct drm_suballoc_manager base; | 13 | struct drm_suballoc_manager base; |
| 14 | struct xe_bo *bo; | 14 | struct xe_bo *bo; |
| 15 | struct xe_bo *shadow; | ||
| 16 | /** @swap_guard: Timeline guard updating @bo and @shadow */ | ||
| 17 | struct mutex swap_guard; | ||
| 15 | void *cpu_ptr; | 18 | void *cpu_ptr; |
| 16 | bool is_iomem; | 19 | bool is_iomem; |
| 17 | }; | 20 | }; |
| @@ -358,7 +358,7 @@ ssize_t xe_sriov_packet_write_single(struct xe_device *xe, unsigned int vfid, · 357 unmodified lines | |||
| 358 | 358 | ||
| 359 | #define MIGRATION_DESCRIPTOR_DWORDS (GUC_KLV_LEN_MIN + MIGRATION_KLV_DEVICE_DEVID_LEN + \ | 359 | #define MIGRATION_DESCRIPTOR_DWORDS (GUC_KLV_LEN_MIN + MIGRATION_KLV_DEVICE_DEVID_LEN + \ |
| 360 | GUC_KLV_LEN_MIN + MIGRATION_KLV_DEVICE_REVID_LEN) | 360 | GUC_KLV_LEN_MIN + MIGRATION_KLV_DEVICE_REVID_LEN) |
| 361 | static size_t pf_descriptor_init(struct xe_device *xe, unsigned int vfid) | 361 | static int pf_descriptor_init(struct xe_device *xe, unsigned int vfid) |
| 362 | { | 362 | { |
| 363 | struct xe_sriov_packet **desc = pf_pick_descriptor(xe, vfid); | 363 | struct xe_sriov_packet **desc = pf_pick_descriptor(xe, vfid); |
| 364 | struct xe_sriov_packet *data; | 364 | struct xe_sriov_packet *data; |
| @@ -90,6 +90,7 @@ bool xe_sriov_pf_readiness(struct xe_device *xe) · 89 unmodified lines | |||
| 90 | */ | 90 | */ |
| 91 | int xe_sriov_pf_init_early(struct xe_device *xe) | 91 | int xe_sriov_pf_init_early(struct xe_device *xe) |
| 92 | { | 92 | { |
| 93 | struct xe_mert *mert = &xe_device_get_root_tile(xe)->mert; | ||
| 93 | int err; | 94 | int err; |
| 94 | 95 | ||
| 95 | xe_assert(xe, IS_SRIOV_PF(xe)); | 96 | xe_assert(xe, IS_SRIOV_PF(xe)); |
| @@ -111,6 +112,9 @@ int xe_sriov_pf_init_early(struct xe_device *xe) · 15 unmodified lines | |||
| 111 | 112 | ||
| 112 | xe_sriov_pf_service_init(xe); | 113 | xe_sriov_pf_service_init(xe); |
| 113 | 114 | ||
| 115 | spin_lock_init(&mert->lock); | ||
| 116 | init_completion(&mert->tlb_inv_done); | ||
| 117 | |||
| 114 | return 0; | 118 | return 0; |
| 115 | } | 119 | } |
| 116 | 120 | ||
| @@ -70,9 +70,8 @@ static ssize_t from_file_write_to_xe_call(struct file *file, const char __user * · 69 unmodified lines | |||
| 70 | if (ret < 0) | 70 | if (ret < 0) |
| 71 | return ret; | 71 | return ret; |
| 72 | if (yes) { | 72 | if (yes) { |
| 73 | xe_pm_runtime_get(xe); | 73 | guard(xe_pm_runtime)(xe); |
| 74 | ret = call(xe); | 74 | ret = call(xe); |
| 75 | xe_pm_runtime_put(xe); | ||
| 76 | } | 75 | } |
| 77 | if (ret < 0) | 76 | if (ret < 0) |
| 78 | return ret; | 77 | return ret; |
| @@ -209,9 +208,8 @@ static ssize_t from_file_write_to_vf_call(struct file *file, const char __user * · 130 unmodified lines | |||
| 209 | if (ret < 0) | 208 | if (ret < 0) |
| 210 | return ret; | 209 | return ret; |
| 211 | if (yes) { | 210 | if (yes) { |
| 212 | xe_pm_runtime_get(xe); | 211 | guard(xe_pm_runtime)(xe); |
| 213 | ret = call(xe, vfid); | 212 | ret = call(xe, vfid); |
| 214 | xe_pm_runtime_put(xe); | ||
| 215 | } | 213 | } |
| 216 | if (ret < 0) | 214 | if (ret < 0) |
| 217 | return ret; | 215 | return ret; |
| @@ -389,16 +389,12 @@ static ssize_t xe_sriov_dev_attr_store(struct kobject *kobj, struct attribute *a · 388 unmodified lines | |||
| 389 | struct xe_sriov_dev_attr *vattr = to_xe_sriov_dev_attr(attr); | 389 | struct xe_sriov_dev_attr *vattr = to_xe_sriov_dev_attr(attr); |
| 390 | struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); | 390 | struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); |
| 391 | struct xe_device *xe = vkobj->xe; | 391 | struct xe_device *xe = vkobj->xe; |
| 392 | ssize_t ret; | ||
| 393 | 392 | ||
| 394 | if (!vattr->store) | 393 | if (!vattr->store) |
| 395 | return -EPERM; | 394 | return -EPERM; |
| 396 | 395 | ||
| 397 | xe_pm_runtime_get(xe); | 396 | guard(xe_pm_runtime)(xe); |
| 398 | ret = xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, buf, count); | 397 | return xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, buf, count); |
| 399 | xe_pm_runtime_put(xe); | ||
| 400 | |||
| 401 | return ret; | ||
| 402 | } | 398 | } |
| 403 | 399 | ||
| 404 | static ssize_t xe_sriov_vf_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) | 400 | static ssize_t xe_sriov_vf_attr_show(struct kobject *kobj, struct attribute *attr, char *buf) |
| @@ -423,18 +419,14 @@ static ssize_t xe_sriov_vf_attr_store(struct kobject *kobj, struct attribute *at · 18 unmodified lines | |||
| 423 | struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); | 419 | struct xe_sriov_kobj *vkobj = to_xe_sriov_kobj(kobj); |
| 424 | struct xe_device *xe = vkobj->xe; | 420 | struct xe_device *xe = vkobj->xe; |
| 425 | unsigned int vfid = vkobj->vfid; | 421 | unsigned int vfid = vkobj->vfid; |
| 426 | ssize_t ret; | ||
| 427 | 422 | ||
| 428 | xe_sriov_pf_assert_vfid(xe, vfid); | 423 | xe_sriov_pf_assert_vfid(xe, vfid); |
| 429 | 424 | ||
| 430 | if (!vattr->store) | 425 | if (!vattr->store) |
| 431 | return -EPERM; | 426 | return -EPERM; |
| 432 | 427 | ||
| 433 | xe_pm_runtime_get(xe); | 428 | guard(xe_pm_runtime)(xe); |
| 434 | ret = xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, vfid, buf, count); | 429 | return xe_sriov_pf_wait_ready(xe) ?: vattr->store(xe, vfid, buf, count); |
| 435 | xe_pm_runtime_get(xe); | ||
| 436 | |||
| 437 | return ret; | ||
| 438 | } | 430 | } |
| 439 | 431 | ||
| 440 | static const struct sysfs_ops xe_sriov_dev_sysfs_ops = { | 432 | static const struct sysfs_ops xe_sriov_dev_sysfs_ops = { |
| @@ -49,11 +49,13 @@ · 48 unmodified lines | |||
| 49 | * | 49 | * |
| 50 | * As soon as Virtual GPU of the VM starts, the VF driver within receives | 50 | * As soon as Virtual GPU of the VM starts, the VF driver within receives |
| 51 | * the MIGRATED interrupt and schedules post-migration recovery worker. | 51 | * the MIGRATED interrupt and schedules post-migration recovery worker. |
| 52 | * That worker queries GuC for new provisioning (using MMIO communication), | 52 | * That worker sends `VF2GUC_RESFIX_START` action along with non-zero |
| 53 | * marker, queries GuC for new provisioning (using MMIO communication), | ||
| 53 | * and applies fixups to any non-virtualized resources used by the VF. | 54 | * and applies fixups to any non-virtualized resources used by the VF. |
| 54 | * | 55 | * |
| 55 | * When the VF driver is ready to continue operation on the newly connected | 56 | * When the VF driver is ready to continue operation on the newly connected |
| 56 | * hardware, it sends `VF2GUC_NOTIFY_RESFIX_DONE` which causes it to | 57 | * hardware, it sends `VF2GUC_RESFIX_DONE` action along with the same |
| 58 | * marker which was sent with `VF2GUC_RESFIX_START` which causes it to | ||
| 57 | * enter the long awaited `VF_RUNNING` state, and therefore start handling | 59 | * enter the long awaited `VF_RUNNING` state, and therefore start handling |
| 58 | * CTB messages and scheduling workloads from the VF:: | 60 | * CTB messages and scheduling workloads from the VF:: |
| 59 | * | 61 | * |
| @@ -102,12 +104,17 @@ · 42 unmodified lines | |||
| 102 | * | [ ] new VF provisioning [ ] | 104 | * | [ ] new VF provisioning [ ] |
| 103 | * | [ ]---------------------------> [ ] | 105 | * | [ ]---------------------------> [ ] |
| 104 | * | | [ ] | 106 | * | | [ ] |
| 107 | * | | VF2GUC_RESFIX_START [ ] | ||
| 108 | * | [ ] <---------------------------[ ] | ||
| 109 | * | [ ] [ ] | ||
| 110 | * | [ ] success [ ] | ||
| 111 | * | [ ]---------------------------> [ ] | ||
| 105 | * | | VF driver applies post [ ] | 112 | * | | VF driver applies post [ ] |
| 106 | * | | migration fixups -------[ ] | 113 | * | | migration fixups -------[ ] |
| 107 | * | | | [ ] | 114 | * | | | [ ] |
| 108 | * | | -----> [ ] | 115 | * | | -----> [ ] |
| 109 | * | | [ ] | 116 | * | | [ ] |
| 110 | * | | VF2GUC_NOTIFY_RESFIX_DONE [ ] | 117 | * | | VF2GUC_RESFIX_DONE [ ] |
| 111 | * | [ ] <---------------------------[ ] | 118 | * | [ ] <---------------------------[ ] |
| 112 | * | [ ] [ ] | 119 | * | [ ] [ ] |
| 113 | * | [ ] GuC sets new VF state to [ ] | 120 | * | [ ] GuC sets new VF state to [ ] |
| @@ -118,6 +125,55 @@ · 4 unmodified lines | |||
| 118 | * | [ ]---------------------------> [ ] | 125 | * | [ ]---------------------------> [ ] |
| 119 | * | | | | 126 | * | | | |
| 120 | * | | | | 127 | * | | | |
| 128 | * | ||
| 129 | * Handling of VF double migration flow is shown below:: | ||
| 130 | * | ||
| 131 | * GuC1 VF | ||
| 132 | * | | | ||
| 133 | * | [ ]<--- start fixups | ||
| 134 | * | VF2GUC_RESFIX_START(marker) [ ] | ||
| 135 | * [ ] <-------------------------------------------[ ] | ||
| 136 | * [ ] [ ] | ||
| 137 | * [ ]---\ [ ] | ||
| 138 | * [ ] store marker [ ] | ||
| 139 | * [ ]<--/ [ ] | ||
| 140 | * [ ] [ ] | ||
| 141 | * [ ] success [ ] | ||
| 142 | * [ ] ------------------------------------------> [ ] | ||
| 143 | * | [ ] | ||
| 144 | * | [ ]---\ | ||
| 145 | * | [ ] do fixups | ||
| 146 | * | [ ]<--/ | ||
| 147 | * | [ ] | ||
| 148 | * -------------- VF paused / saved ---------------- | ||
| 149 | * : | ||
| 150 | * | ||
| 151 | * GuC2 | ||
| 152 | * | | ||
| 153 | * ----------------- VF restored ------------------ | ||
| 154 | * | | ||
| 155 | * [ ] | ||
| 156 | * [ ]---\ | ||
| 157 | * [ ] reset marker | ||
| 158 | * [ ]<--/ | ||
| 159 | * [ ] | ||
| 160 | * ----------------- VF resumed ------------------ | ||
| 161 | * | [ ] | ||
| 162 | * | [ ] | ||
| 163 | * | VF2GUC_RESFIX_DONE(marker) [ ] | ||
| 164 | * [ ] <-------------------------------------------[ ] | ||
| 165 | * [ ] [ ] | ||
| 166 | * [ ]---\ [ ] | ||
| 167 | * [ ] check marker [ ] | ||
| 168 | * [ ] (mismatch) [ ] | ||
| 169 | * [ ]<--/ [ ] | ||
| 170 | * [ ] [ ] | ||
| 171 | * [ ] RESPONSE_VF_MIGRATED [ ] | ||
| 172 | * [ ] ------------------------------------------> [ ] | ||
| 173 | * | [ ]---\ | ||
| 174 | * | [ ] reschedule fixups | ||
| 175 | * | [ ]<--/ | ||
| 176 | * | | | ||
| 121 | */ | 177 | */ |
| 122 | 178 | ||
| 123 | /** | 179 | /** |
| @@ -170,6 +226,26 @@ void xe_sriov_vf_init_early(struct xe_device *xe) · 46 unmodified lines | |||
| 170 | vf_migration_init_early(xe); | 226 | vf_migration_init_early(xe); |
| 171 | } | 227 | } |
| 172 | 228 | ||
| 229 | static int vf_migration_init_late(struct xe_device *xe) | ||
| 230 | { | ||
| 231 | struct xe_gt *gt = xe_root_mmio_gt(xe); | ||
| 232 | struct xe_uc_fw_version guc_version; | ||
| 233 | |||
| 234 | if (!xe_sriov_vf_migration_supported(xe)) | ||
| 235 | return 0; | ||
| 236 | |||
| 237 | xe_gt_sriov_vf_guc_versions(gt, NULL, &guc_version); | ||
| 238 | if (MAKE_GUC_VER_STRUCT(guc_version) < MAKE_GUC_VER(1, 27, 0)) { | ||
| 239 | xe_sriov_vf_migration_disable(xe, | ||
| 240 | "requires GuC ABI >= 1.27.0, but only %u.%u.%u found", | ||
| 241 | guc_version.major, guc_version.minor, | ||
| 242 | guc_version.patch); | ||
| 243 | return 0; | ||
| 244 | } | ||
| 245 | |||
| 246 | return xe_sriov_vf_ccs_init(xe); | ||
| 247 | } | ||
| 248 | |||
| 173 | /** | 249 | /** |
| 174 | * xe_sriov_vf_init_late() - SR-IOV VF late initialization functions. | 250 | * xe_sriov_vf_init_late() - SR-IOV VF late initialization functions. |
| 175 | * @xe: the &xe_device to initialize | 251 | * @xe: the &xe_device to initialize |
| @@ -180,7 +256,7 @@ void xe_sriov_vf_init_early(struct xe_device *xe) · 4 unmodified lines | |||
| 180 | */ | 256 | */ |
| 181 | int xe_sriov_vf_init_late(struct xe_device *xe) | 257 | int xe_sriov_vf_init_late(struct xe_device *xe) |
| 182 | { | 258 | { |
| 183 | return xe_sriov_vf_ccs_init(xe); | 259 | return vf_migration_init_late(xe); |
| 184 | } | 260 | } |
| 185 | 261 | ||
| 186 | static int sa_info_vf_ccs(struct seq_file *m, void *data) | 262 | static int sa_info_vf_ccs(struct seq_file *m, void *data) |
| @@ -150,7 +150,8 @@ static int alloc_bb_pool(struct xe_tile *tile, struct xe_sriov_vf_ccs_ctx *ctx) · 149 unmodified lines | |||
| 150 | xe_sriov_info(xe, "Allocating %s CCS BB pool size = %lldMB\n", | 150 | xe_sriov_info(xe, "Allocating %s CCS BB pool size = %lldMB\n", |
| 151 | ctx->ctx_id ? "Restore" : "Save", bb_pool_size / SZ_1M); | 151 | ctx->ctx_id ? "Restore" : "Save", bb_pool_size / SZ_1M); |
| 152 | 152 | ||
| 153 | sa_manager = xe_sa_bo_manager_init(tile, bb_pool_size, SZ_16); | 153 | sa_manager = __xe_sa_bo_manager_init(tile, bb_pool_size, SZ_4K, SZ_16, |
| 154 | XE_SA_BO_MANAGER_FLAG_SHADOW); | ||
| 154 | 155 | ||
| 155 | if (IS_ERR(sa_manager)) { | 156 | if (IS_ERR(sa_manager)) { |
| 156 | xe_sriov_err(xe, "Suballocator init failed with error: %pe\n", | 157 | xe_sriov_err(xe, "Suballocator init failed with error: %pe\n", |
| @@ -162,9 +163,12 @@ static int alloc_bb_pool(struct xe_tile *tile, struct xe_sriov_vf_ccs_ctx *ctx) · 5 unmodified lines | |||
| 162 | offset = 0; | 163 | offset = 0; |
| 163 | xe_map_memset(xe, &sa_manager->bo->vmap, offset, MI_NOOP, | 164 | xe_map_memset(xe, &sa_manager->bo->vmap, offset, MI_NOOP, |
| 164 | bb_pool_size); | 165 | bb_pool_size); |
| 166 | xe_map_memset(xe, &sa_manager->shadow->vmap, offset, MI_NOOP, | ||
| 167 | bb_pool_size); | ||
| 165 | 168 | ||
| 166 | offset = bb_pool_size - sizeof(u32); | 169 | offset = bb_pool_size - sizeof(u32); |
| 167 | xe_map_wr(xe, &sa_manager->bo->vmap, offset, u32, MI_BATCH_BUFFER_END); | 170 | xe_map_wr(xe, &sa_manager->bo->vmap, offset, u32, MI_BATCH_BUFFER_END); |
| 171 | xe_map_wr(xe, &sa_manager->shadow->vmap, offset, u32, MI_BATCH_BUFFER_END); | ||
| 168 | 172 | ||
| 169 | ctx->mem.ccs_bb_pool = sa_manager; | 173 | ctx->mem.ccs_bb_pool = sa_manager; |
| 170 | 174 | ||
| @@ -381,6 +385,18 @@ err_ret: · 210 unmodified lines | |||
| 381 | return err; | 385 | return err; |
| 382 | } | 386 | } |
| 383 | 387 | ||
| 388 | #define XE_SRIOV_VF_CCS_RW_BB_ADDR_OFFSET (2 * sizeof(u32)) | ||
| 389 | void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx) | ||
| 390 | { | ||
| 391 | u64 addr = xe_sa_manager_gpu_addr(ctx->mem.ccs_bb_pool); | ||
| 392 | struct xe_lrc *lrc = xe_exec_queue_lrc(ctx->mig_q); | ||
| 393 | struct xe_device *xe = gt_to_xe(ctx->mig_q->gt); | ||
| 394 | |||
| 395 | xe_device_wmb(xe); | ||
| 396 | xe_map_wr(xe, &lrc->bo->vmap, XE_SRIOV_VF_CCS_RW_BB_ADDR_OFFSET, u32, addr); | ||
| 397 | xe_device_wmb(xe); | ||
| 398 | } | ||
| 399 | |||
| 384 | /** | 400 | /** |
| 385 | * xe_sriov_vf_ccs_attach_bo - Insert CCS read write commands in the BO. | 401 | * xe_sriov_vf_ccs_attach_bo - Insert CCS read write commands in the BO. |
| 386 | * @bo: the &buffer object to which batch buffer commands will be added. | 402 | * @bo: the &buffer object to which batch buffer commands will be added. |
| @@ -441,9 +457,7 @@ int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo) · 54 unmodified lines | |||
| 441 | if (!bb) | 457 | if (!bb) |
| 442 | continue; | 458 | continue; |
| 443 | 459 | ||
| 444 | memset(bb->cs, MI_NOOP, bb->len * sizeof(u32)); | 460 | xe_migrate_ccs_rw_copy_clear(bo, ctx_id); |
| 445 | xe_bb_free(bb, NULL); | ||
| 446 | bo->bb_ccs[ctx_id] = NULL; | ||
| 447 | } | 461 | } |
| 448 | return 0; | 462 | return 0; |
| 449 | } | 463 | } |
| @@ -463,8 +477,7 @@ void xe_sriov_vf_ccs_print(struct xe_device *xe, struct drm_printer *p) · 13 unmodified lines | |||
| 463 | if (!IS_VF_CCS_READY(xe)) | 477 | if (!IS_VF_CCS_READY(xe)) |
| 464 | return; | 478 | return; |
| 465 | 479 | ||
| 466 | xe_pm_runtime_get(xe); | 480 | guard(xe_pm_runtime)(xe); |
| 467 | |||
| 468 | for_each_ccs_rw_ctx(ctx_id) { | 481 | for_each_ccs_rw_ctx(ctx_id) { |
| 469 | bb_pool = xe->sriov.vf.ccs.contexts[ctx_id].mem.ccs_bb_pool; | 482 | bb_pool = xe->sriov.vf.ccs.contexts[ctx_id].mem.ccs_bb_pool; |
| 470 | if (!bb_pool) | 483 | if (!bb_pool) |
| @@ -475,6 +488,4 @@ void xe_sriov_vf_ccs_print(struct xe_device *xe, struct drm_printer *p) · 4 unmodified lines | |||
| 475 | drm_suballoc_dump_debug_info(&bb_pool->base, p, xe_sa_manager_gpu_addr(bb_pool)); | 488 | drm_suballoc_dump_debug_info(&bb_pool->base, p, xe_sa_manager_gpu_addr(bb_pool)); |
| 476 | drm_puts(p, "\n"); | 489 | drm_puts(p, "\n"); |
| 477 | } | 490 | } |
| 478 | |||
| 479 | xe_pm_runtime_put(xe); | ||
| 480 | } | 491 | } |
| @@ -20,6 +20,7 @@ int xe_sriov_vf_ccs_detach_bo(struct xe_bo *bo); · 19 unmodified lines | |||
| 20 | int xe_sriov_vf_ccs_register_context(struct xe_device *xe); | 20 | int xe_sriov_vf_ccs_register_context(struct xe_device *xe); |
| 21 | void xe_sriov_vf_ccs_rebase(struct xe_device *xe); | 21 | void xe_sriov_vf_ccs_rebase(struct xe_device *xe); |
| 22 | void xe_sriov_vf_ccs_print(struct xe_device *xe, struct drm_printer *p); | 22 | void xe_sriov_vf_ccs_print(struct xe_device *xe, struct drm_printer *p); |
| 23 | void xe_sriov_vf_ccs_rw_update_bb_addr(struct xe_sriov_vf_ccs_ctx *ctx); | ||
| 23 | 24 | ||
| 24 | static inline bool xe_sriov_vf_ccs_ready(struct xe_device *xe) | 25 | static inline bool xe_sriov_vf_ccs_ready(struct xe_device *xe) |
| 25 | { | 26 | { |
| @@ -16,11 +16,10 @@ · 15 unmodified lines | |||
| 16 | #include "xe_heci_gsc.h" | 16 | #include "xe_heci_gsc.h" |
| 17 | #include "xe_i2c.h" | 17 | #include "xe_i2c.h" |
| 18 | #include "xe_mmio.h" | 18 | #include "xe_mmio.h" |
| 19 | #include "xe_nvm.h" | ||
| 19 | #include "xe_pcode_api.h" | 20 | #include "xe_pcode_api.h" |
| 20 | #include "xe_vsec.h" | 21 | #include "xe_vsec.h" |
| 21 | 22 | ||
| 22 | #define MAX_SCRATCH_MMIO 8 | ||
| 23 | |||
| 24 | /** | 23 | /** |
| 25 | * DOC: Survivability Mode | 24 | * DOC: Survivability Mode |
| 26 | * | 25 | * |
| @@ -48,19 +47,43 @@ · 21 unmodified lines | |||
| 48 | * | 47 | * |
| 49 | * Refer :ref:`xe_configfs` for more details on how to use configfs | 48 | * Refer :ref:`xe_configfs` for more details on how to use configfs |
| 50 | * | 49 | * |
| 51 | * Survivability mode is indicated by the below admin-only readable sysfs which provides additional | 50 | * Survivability mode is indicated by the below admin-only readable sysfs entry. It |
| 52 | * debug information:: | 51 | * provides information about the type of survivability mode (Boot/Runtime). |
| 52 | * | ||
| 53 | * .. code-block:: shell | ||
| 54 | * | ||
| 55 | * # cat /sys/bus/pci/devices/<device>/survivability_mode | ||
| 56 | * Boot | ||
| 57 | * | ||
| 58 | * | ||
| 59 | * Any additional debug information if present will be visible under the directory | ||
| 60 | * ``survivability_info``:: | ||
| 61 | * | ||
| 62 | * /sys/bus/pci/devices/<device>/survivability_info/ | ||
| 63 | * ├── aux_info0 | ||
| 64 | * ├── aux_info1 | ||
| 65 | * ├── aux_info2 | ||
| 66 | * ├── aux_info3 | ||
| 67 | * ├── aux_info4 | ||
| 68 | * ├── capability_info | ||
| 69 | * ├── fdo_mode | ||
| 70 | * ├── postcode_trace | ||
| 71 | * └── postcode_trace_overflow | ||
| 72 | * | ||
| 73 | * This directory has the following attributes | ||
| 74 | * | ||
| 75 | * - ``capability_info`` : Indicates Boot status and support for additional information | ||
| 53 | * | 76 | * |
| 54 | * /sys/bus/pci/devices/<device>/survivability_mode | 77 | * - ``postcode_trace``, ``postcode_trace_overflow`` : Each postcode is a 8bit value and |
| 78 | * represents a boot failure event. When a new failure event is logged by PCODE the | ||
| 79 | * existing postcodes are shifted left. These entries provide a history of 8 postcodes. | ||
| 55 | * | 80 | * |
| 56 | * Capability Information: | 81 | * - ``aux_info<n>`` : Some failures have additional debug information |
| 57 | * Provides boot status | 82 | * |
| 58 | * Postcode Information: | 83 | * - ``fdo_mode`` : To allow recovery in scenarios where MEI itself fails, a new SPI Flash |
| 59 | * Provides information about the failure | 84 | * Descriptor Override (FDO) mode is added in v2 survivability breadcrumbs. This mode is enabled |
| 60 | * Overflow Information | 85 | * by PCODE and provides the ability to directly update the firmware via SPI Driver without |
| 61 | * Provides history of previous failures | 86 | * any dependency on MEI. Xe KMD initializes the nvm aux driver if FDO mode is enabled. |
| 62 | * Auxiliary Information | ||
| 63 | * Certain failures may have information in addition to postcode information | ||
| 64 | * | 87 | * |
| 65 | * Runtime Survivability | 88 | * Runtime Survivability |
| 66 | * ===================== | 89 | * ===================== |
| @@ -68,61 +91,77 @@ · 1 unmodified line | |||
| 68 | * Certain runtime firmware errors can cause the device to enter a wedged state | 91 | * Certain runtime firmware errors can cause the device to enter a wedged state |
| 69 | * (:ref:`xe-device-wedging`) requiring a firmware flash to restore normal operation. | 92 | * (:ref:`xe-device-wedging`) requiring a firmware flash to restore normal operation. |
| 70 | * Runtime Survivability Mode indicates that a firmware flash is necessary to recover the device and | 93 | * Runtime Survivability Mode indicates that a firmware flash is necessary to recover the device and |
| 71 | * is indicated by the presence of survivability mode sysfs:: | 94 | * is indicated by the presence of survivability mode sysfs. |
| 95 | * Survivability mode sysfs provides information about the type of survivability mode. | ||
| 72 | * | 96 | * |
| 73 | * /sys/bus/pci/devices/<device>/survivability_mode | 97 | * .. code-block:: shell |
| 74 | * | 98 | * |
| 75 | * Survivability mode sysfs provides information about the type of survivability mode. | 99 | * # cat /sys/bus/pci/devices/<device>/survivability_mode |
| 100 | * Runtime | ||
| 76 | * | 101 | * |
| 77 | * When such errors occur, userspace is notified with the drm device wedged uevent and runtime | 102 | * When such errors occur, userspace is notified with the drm device wedged uevent and runtime |
| 78 | * survivability mode. User can then initiate a firmware flash using userspace tools like fwupd | 103 | * survivability mode. User can then initiate a firmware flash using userspace tools like fwupd |
| 79 | * to restore device to normal operation. | 104 | * to restore device to normal operation. |
| 80 | */ | 105 | */ |
| 81 | 106 | ||
| 82 | static u32 aux_history_offset(u32 reg_value) | 107 | static const char * const reg_map[] = { |
| 108 | [CAPABILITY_INFO] = "Capability Info", | ||
| 109 | [POSTCODE_TRACE] = "Postcode trace", | ||
| 110 | [POSTCODE_TRACE_OVERFLOW] = "Postcode trace overflow", | ||
| 111 | [AUX_INFO0] = "Auxiliary Info 0", | ||
| 112 | [AUX_INFO1] = "Auxiliary Info 1", | ||
| 113 | [AUX_INFO2] = "Auxiliary Info 2", | ||
| 114 | [AUX_INFO3] = "Auxiliary Info 3", | ||
| 115 | [AUX_INFO4] = "Auxiliary Info 4", | ||
| 116 | }; | ||
| 117 | |||
| 118 | #define FDO_INFO (MAX_SCRATCH_REG + 1) | ||
| 119 | |||
| 120 | struct xe_survivability_attribute { | ||
| 121 | struct device_attribute attr; | ||
| 122 | u8 index; | ||
| 123 | }; | ||
| 124 | |||
| 125 | static struct | ||
| 126 | xe_survivability_attribute *dev_attr_to_survivability_attr(struct device_attribute *attr) | ||
| 83 | { | 127 | { |
| 84 | return REG_FIELD_GET(AUXINFO_HISTORY_OFFSET, reg_value); | 128 | return container_of(attr, struct xe_survivability_attribute, attr); |
| 85 | } | 129 | } |
| 86 | 130 | ||
| 87 | static void set_survivability_info(struct xe_mmio *mmio, struct xe_survivability_info *info, | 131 | static void set_survivability_info(struct xe_mmio *mmio, u32 *info, int id) |
| 88 | int id, char *name) | ||
| 89 | { | 132 | { |
| 90 | strscpy(info[id].name, name, sizeof(info[id].name)); | 133 | info[id] = xe_mmio_read32(mmio, PCODE_SCRATCH(id)); |
| 91 | info[id].reg = PCODE_SCRATCH(id).raw; | ||
| 92 | info[id].value = xe_mmio_read32(mmio, PCODE_SCRATCH(id)); | ||
| 93 | } | 134 | } |
| 94 | 135 | ||
| 95 | static void populate_survivability_info(struct xe_device *xe) | 136 | static void populate_survivability_info(struct xe_device *xe) |
| 96 | { | 137 | { |
| 97 | struct xe_survivability *survivability = &xe->survivability; | 138 | struct xe_survivability *survivability = &xe->survivability; |
| 98 | struct xe_survivability_info *info = survivability->info; | 139 | u32 *info = survivability->info; |
| 99 | struct xe_mmio *mmio; | 140 | struct xe_mmio *mmio; |
| 100 | u32 id = 0, reg_value; | 141 | u32 id = 0, reg_value; |
| 101 | char name[NAME_MAX]; | ||
| 102 | int index; | ||
| 103 | 142 | ||
| 104 | mmio = xe_root_tile_mmio(xe); | 143 | mmio = xe_root_tile_mmio(xe); |
| 105 | set_survivability_info(mmio, info, id, "Capability Info"); | 144 | set_survivability_info(mmio, info, CAPABILITY_INFO); |
| 106 | reg_value = info[id].value; | 145 | reg_value = info[CAPABILITY_INFO]; |
| 146 | |||
| 147 | survivability->version = REG_FIELD_GET(BREADCRUMB_VERSION, reg_value); | ||
| 148 | /* FDO mode is exposed only from version 2 */ | ||
| 149 | if (survivability->version >= 2) | ||
| 150 | survivability->fdo_mode = REG_FIELD_GET(FDO_MODE, reg_value); | ||
| 107 | 151 | ||
| 108 | if (reg_value & HISTORY_TRACKING) { | 152 | if (reg_value & HISTORY_TRACKING) { |
| 109 | id++; | 153 | set_survivability_info(mmio, info, POSTCODE_TRACE); |
| 110 | set_survivability_info(mmio, info, id, "Postcode Info"); | ||
| 111 | 154 | ||
| 112 | if (reg_value & OVERFLOW_SUPPORT) { | 155 | if (reg_value & OVERFLOW_SUPPORT) |
| 113 | id = REG_FIELD_GET(OVERFLOW_REG_OFFSET, reg_value); | 156 | set_survivability_info(mmio, info, POSTCODE_TRACE_OVERFLOW); |
| 114 | set_survivability_info(mmio, info, id, "Overflow Info"); | ||
| 115 | } | ||
| 116 | } | 157 | } |
| 117 | 158 | ||
| 159 | /* Traverse the linked list of aux info registers */ | ||
| 118 | if (reg_value & AUXINFO_SUPPORT) { | 160 | if (reg_value & AUXINFO_SUPPORT) { |
| 119 | id = REG_FIELD_GET(AUXINFO_REG_OFFSET, reg_value); | 161 | for (id = REG_FIELD_GET(AUXINFO_REG_OFFSET, reg_value); |
| 120 | 162 | id >= AUX_INFO0 && id < MAX_SCRATCH_REG; | |
| 121 | for (index = 0; id && reg_value; index++, reg_value = info[id].value, | 163 | id = REG_FIELD_GET(AUXINFO_HISTORY_OFFSET, info[id])) |
| 122 | id = aux_history_offset(reg_value)) { | 164 | set_survivability_info(mmio, info, id); |
| 123 | snprintf(name, NAME_MAX, "Auxiliary Info %d", index); | ||
| 124 | set_survivability_info(mmio, info, id, name); | ||
| 125 | } | ||
| 126 | } | 165 | } |
| 127 | } | 166 | } |
| 128 | 167 | ||
| @@ -130,15 +169,14 @@ static void log_survivability_info(struct pci_dev *pdev) · 1 unmodified line | |||
| 130 | { | 169 | { |
| 131 | struct xe_device *xe = pdev_to_xe_device(pdev); | 170 | struct xe_device *xe = pdev_to_xe_device(pdev); |
| 132 | struct xe_survivability *survivability = &xe->survivability; | 171 | struct xe_survivability *survivability = &xe->survivability; |
| 133 | struct xe_survivability_info *info = survivability->info; | 172 | u32 *info = survivability->info; |
| 134 | int id; | 173 | int id; |
| 135 | 174 | ||
| 136 | dev_info(&pdev->dev, "Survivability Boot Status : Critical Failure (%d)\n", | 175 | dev_info(&pdev->dev, "Survivability Boot Status : Critical Failure (%d)\n", |
| 137 | survivability->boot_status); | 176 | survivability->boot_status); |
| 138 | for (id = 0; id < MAX_SCRATCH_MMIO; id++) { | 177 | for (id = 0; id < MAX_SCRATCH_REG; id++) { |
| 139 | if (info[id].reg) | 178 | if (info[id]) |
| 140 | dev_info(&pdev->dev, "%s: 0x%x - 0x%x\n", info[id].name, | 179 | dev_info(&pdev->dev, "%s: 0x%x\n", reg_map[id], info[id]); |
| 141 | info[id].reg, info[id].value); | ||
| 142 | } | 180 | } |
| 143 | } | 181 | } |
| 144 | 182 | ||
| @@ -156,43 +194,103 @@ static ssize_t survivability_mode_show(struct device *dev, · 11 unmodified lines | |||
| 156 | struct pci_dev *pdev = to_pci_dev(dev); | 194 | struct pci_dev *pdev = to_pci_dev(dev); |
| 157 | struct xe_device *xe = pdev_to_xe_device(pdev); | 195 | struct xe_device *xe = pdev_to_xe_device(pdev); |
| 158 | struct xe_survivability *survivability = &xe->survivability; | 196 | struct xe_survivability *survivability = &xe->survivability; |
| 159 | struct xe_survivability_info *info = survivability->info; | ||
| 160 | int index = 0, count = 0; | ||
| 161 | 197 | ||
| 162 | count += sysfs_emit_at(buff, count, "Survivability mode type: %s\n", | 198 | return sysfs_emit(buff, "%s\n", survivability->type ? "Runtime" : "Boot"); |
| 163 | survivability->type ? "Runtime" : "Boot"); | 199 | } |
| 200 | |||
| 201 | static DEVICE_ATTR_ADMIN_RO(survivability_mode); | ||
| 164 | 202 | ||
| 165 | if (!check_boot_failure(xe)) | 203 | static ssize_t survivability_info_show(struct device *dev, |
| 166 | return count; | 204 | struct device_attribute *attr, char *buff) |
| 205 | { | ||
| 206 | struct xe_survivability_attribute *sa = dev_attr_to_survivability_attr(attr); | ||
| 207 | struct pci_dev *pdev = to_pci_dev(dev); | ||
| 208 | struct xe_device *xe = pdev_to_xe_device(pdev); | ||
| 209 | struct xe_survivability *survivability = &xe->survivability; | ||
| 210 | u32 *info = survivability->info; | ||
| 167 | 211 | ||
| 168 | for (index = 0; index < MAX_SCRATCH_MMIO; index++) { | 212 | if (sa->index == FDO_INFO) |
| 169 | if (info[index].reg) | 213 | return sysfs_emit(buff, "%s\n", str_enabled_disabled(survivability->fdo_mode)); |
| 170 | count += sysfs_emit_at(buff, count, "%s: 0x%x - 0x%x\n", info[index].name, | ||
| 171 | info[index].reg, info[index].value); | ||
| 172 | } | ||
| 173 | 214 | ||
| 174 | return count; | 215 | return sysfs_emit(buff, "0x%x\n", info[sa->index]); |
| 175 | } | 216 | } |
| 176 | 217 | ||
| 177 | static DEVICE_ATTR_ADMIN_RO(survivability_mode); | 218 | #define SURVIVABILITY_ATTR_RO(name, _index) \ |
| 219 | struct xe_survivability_attribute attr_##name = { \ | ||
| 220 | .attr = __ATTR(name, 0400, survivability_info_show, NULL), \ | ||
| 221 | .index = _index, \ | ||
| 222 | } | ||
| 223 | |||
| 224 | static SURVIVABILITY_ATTR_RO(capability_info, CAPABILITY_INFO); | ||
| 225 | static SURVIVABILITY_ATTR_RO(postcode_trace, POSTCODE_TRACE); | ||
| 226 | static SURVIVABILITY_ATTR_RO(postcode_trace_overflow, POSTCODE_TRACE_OVERFLOW); | ||
| 227 | static SURVIVABILITY_ATTR_RO(aux_info0, AUX_INFO0); | ||
| 228 | static SURVIVABILITY_ATTR_RO(aux_info1, AUX_INFO1); | ||
| 229 | static SURVIVABILITY_ATTR_RO(aux_info2, AUX_INFO2); | ||
| 230 | static SURVIVABILITY_ATTR_RO(aux_info3, AUX_INFO3); | ||
| 231 | static SURVIVABILITY_ATTR_RO(aux_info4, AUX_INFO4); | ||
| 232 | static SURVIVABILITY_ATTR_RO(fdo_mode, FDO_INFO); | ||
| 178 | 233 | ||
| 179 | static void xe_survivability_mode_fini(void *arg) | 234 | static void xe_survivability_mode_fini(void *arg) |
| 180 | { | 235 | { |
| 181 | struct xe_device *xe = arg; | 236 | struct xe_device *xe = arg; |
| 237 | struct xe_survivability *survivability = &xe->survivability; | ||
| 182 | struct pci_dev *pdev = to_pci_dev(xe->drm.dev); | 238 | struct pci_dev *pdev = to_pci_dev(xe->drm.dev); |
| 183 | struct device *dev = &pdev->dev; | 239 | struct device *dev = &pdev->dev; |
| 184 | 240 | ||
| 185 | sysfs_remove_file(&dev->kobj, &dev_attr_survivability_mode.attr); | 241 | if (survivability->fdo_mode) |
| 242 | xe_nvm_fini(xe); | ||
| 243 | |||
| 244 | device_remove_file(dev, &dev_attr_survivability_mode); | ||
| 245 | } | ||
| 246 | |||
| 247 | static umode_t survivability_info_attrs_visible(struct kobject *kobj, struct attribute *attr, | ||
| 248 | int idx) | ||
| 249 | { | ||
| 250 | struct xe_device *xe = kdev_to_xe_device(kobj_to_dev(kobj)); | ||
| 251 | struct xe_survivability *survivability = &xe->survivability; | ||
| 252 | u32 *info = survivability->info; | ||
| 253 | |||
| 254 | /* | ||
| 255 | * Last index in survivability_info_attrs is fdo mode and is applicable only in | ||
| 256 | * version 2 of survivability mode | ||
| 257 | */ | ||
| 258 | if (idx == MAX_SCRATCH_REG && survivability->version >= 2) | ||
| 259 | return 0400; | ||
| 260 | |||
| 261 | if (idx < MAX_SCRATCH_REG && info[idx]) | ||
| 262 | return 0400; | ||
| 263 | |||
| 264 | return 0; | ||
| 186 | } | 265 | } |
| 187 | 266 | ||
| 267 | /* Attributes are ordered according to enum scratch_reg */ | ||
| 268 | static struct attribute *survivability_info_attrs[] = { | ||
| 269 | &attr_capability_info.attr.attr, | ||
| 270 | &attr_postcode_trace.attr.attr, | ||
| 271 | &attr_postcode_trace_overflow.attr.attr, | ||
| 272 | &attr_aux_info0.attr.attr, | ||
| 273 | &attr_aux_info1.attr.attr, | ||
| 274 | &attr_aux_info2.attr.attr, | ||
| 275 | &attr_aux_info3.attr.attr, | ||
| 276 | &attr_aux_info4.attr.attr, | ||
| 277 | &attr_fdo_mode.attr.attr, | ||
| 278 | NULL, | ||
| 279 | }; | ||
| 280 | |||
| 281 | static const struct attribute_group survivability_info_group = { | ||
| 282 | .name = "survivability_info", | ||
| 283 | .attrs = survivability_info_attrs, | ||
| 284 | .is_visible = survivability_info_attrs_visible, | ||
| 285 | }; | ||
| 286 | |||
| 188 | static int create_survivability_sysfs(struct pci_dev *pdev) | 287 | static int create_survivability_sysfs(struct pci_dev *pdev) |
| 189 | { | 288 | { |
| 190 | struct device *dev = &pdev->dev; | 289 | struct device *dev = &pdev->dev; |
| 191 | struct xe_device *xe = pdev_to_xe_device(pdev); | 290 | struct xe_device *xe = pdev_to_xe_device(pdev); |
| 192 | int ret; | 291 | int ret; |
| 193 | 292 | ||
| 194 | /* create survivability mode sysfs */ | 293 | ret = device_create_file(dev, &dev_attr_survivability_mode); |
| 195 | ret = sysfs_create_file(&dev->kobj, &dev_attr_survivability_mode.attr); | ||
| 196 | if (ret) { | 294 | if (ret) { |
| 197 | dev_warn(dev, "Failed to create survivability sysfs files\n"); | 295 | dev_warn(dev, "Failed to create survivability sysfs files\n"); |
| 198 | return ret; | 296 | return ret; |
| @@ -203,6 +301,12 @@ static int create_survivability_sysfs(struct pci_dev *pdev) · 4 unmodified lines | |||
| 203 | if (ret) | 301 | if (ret) |
| 204 | return ret; | 302 | return ret; |
| 205 | 303 | ||
| 304 | if (check_boot_failure(xe)) { | ||
| 305 | ret = devm_device_add_group(dev, &survivability_info_group); | ||
| 306 | if (ret) | ||
| 307 | return ret; | ||
| 308 | } | ||
| 309 | |||
| 206 | return 0; | 310 | return 0; |
| 207 | } | 311 | } |
| 208 | 312 | ||
| @@ -220,12 +324,16 @@ static int enable_boot_survivability_mode(struct pci_dev *pdev) · 11 unmodified lines | |||
| 220 | /* Make sure xe_heci_gsc_init() knows about survivability mode */ | 324 | /* Make sure xe_heci_gsc_init() knows about survivability mode */ |
| 221 | survivability->mode = true; | 325 | survivability->mode = true; |
| 222 | 326 | ||
| 223 | ret = xe_heci_gsc_init(xe); | 327 | xe_heci_gsc_init(xe); |
| 224 | if (ret) | ||
| 225 | goto err; | ||
| 226 | 328 | ||
| 227 | xe_vsec_init(xe); | 329 | xe_vsec_init(xe); |
| 228 | 330 | ||
| 331 | if (survivability->fdo_mode) { | ||
| 332 | ret = xe_nvm_init(xe); | ||
| 333 | if (ret) | ||
| 334 | goto err; | ||
| 335 | } | ||
| 336 | |||
| 229 | ret = xe_i2c_probe(xe); | 337 | ret = xe_i2c_probe(xe); |
| 230 | if (ret) | 338 | if (ret) |
| 231 | goto err; | 339 | goto err; |
| @@ -235,29 +343,11 @@ static int enable_boot_survivability_mode(struct pci_dev *pdev) · 3 unmodified lines | |||
| 235 | return 0; | 343 | return 0; |
| 236 | 344 | ||
| 237 | err: | 345 | err: |
| 346 | dev_err(dev, "Failed to enable Survivability Mode\n"); | ||
| 238 | survivability->mode = false; | 347 | survivability->mode = false; |
| 239 | return ret; | 348 | return ret; |
| 240 | } | 349 | } |
| 241 | 350 | ||
| 242 | static int init_survivability_mode(struct xe_device *xe) | ||
| 243 | { | ||
| 244 | struct xe_survivability *survivability = &xe->survivability; | ||
| 245 | struct xe_survivability_info *info; | ||
| 246 | |||
| 247 | survivability->size = MAX_SCRATCH_MMIO; | ||
| 248 | |||
| 249 | info = devm_kcalloc(xe->drm.dev, survivability->size, sizeof(*info), | ||
| 250 | GFP_KERNEL); | ||
| 251 | if (!info) | ||
| 252 | return -ENOMEM; | ||
| 253 | |||
| 254 | survivability->info = info; | ||
| 255 | |||
| 256 | populate_survivability_info(xe); | ||
| 257 | |||
| 258 | return 0; | ||
| 259 | } | ||
| 260 | |||
| 261 | /** | 351 | /** |
| 262 | * xe_survivability_mode_is_boot_enabled- check if boot survivability mode is enabled | 352 | * xe_survivability_mode_is_boot_enabled- check if boot survivability mode is enabled |
| 263 | * @xe: xe device instance | 353 | * @xe: xe device instance |
| @@ -325,9 +415,7 @@ int xe_survivability_mode_runtime_enable(struct xe_device *xe) · 61 unmodified lines | |||
| 325 | return -EINVAL; | 415 | return -EINVAL; |
| 326 | } | 416 | } |
| 327 | 417 | ||
| 328 | ret = init_survivability_mode(xe); | 418 | populate_survivability_info(xe); |
| 329 | if (ret) | ||
| 330 | return ret; | ||
| 331 | 419 | ||
| 332 | ret = create_survivability_sysfs(pdev); | 420 | ret = create_survivability_sysfs(pdev); |
| 333 | if (ret) | 421 | if (ret) |
| @@ -356,17 +444,16 @@ int xe_survivability_mode_boot_enable(struct xe_device *xe) · 22 unmodified lines | |||
| 356 | { | 444 | { |
| 357 | struct xe_survivability *survivability = &xe->survivability; | 445 | struct xe_survivability *survivability = &xe->survivability; |
| 358 | struct pci_dev *pdev = to_pci_dev(xe->drm.dev); | 446 | struct pci_dev *pdev = to_pci_dev(xe->drm.dev); |
| 359 | int ret; | ||
| 360 | 447 | ||
| 361 | if (!xe_survivability_mode_is_requested(xe)) | 448 | if (!xe_survivability_mode_is_requested(xe)) |
| 362 | return 0; | 449 | return 0; |
| 363 | 450 | ||
| 364 | ret = init_survivability_mode(xe); | 451 | populate_survivability_info(xe); |
| 365 | if (ret) | ||
| 366 | return ret; | ||
| 367 | 452 | ||
| 368 | /* Log breadcrumbs but do not enter survivability mode for Critical boot errors */ | 453 | /* |
| 369 | if (survivability->boot_status == CRITICAL_FAILURE) { | 454 | * v2 supports survivability mode for critical errors |
| 455 | */ | ||
| 456 | if (survivability->version < 2 && survivability->boot_status == CRITICAL_FAILURE) { | ||
| 370 | log_survivability_info(pdev); | 457 | log_survivability_info(pdev); |
| 371 | return -ENXIO; | 458 | return -ENXIO; |
| 372 | } | 459 | } |
| @@ -9,23 +9,29 @@ · 8 unmodified lines | |||
| 9 | #include <linux/limits.h> | 9 | #include <linux/limits.h> |
| 10 | #include <linux/types.h> | 10 | #include <linux/types.h> |
| 11 | 11 | ||
| 12 | enum scratch_reg { | ||
| 13 | CAPABILITY_INFO, | ||
| 14 | POSTCODE_TRACE, | ||
| 15 | POSTCODE_TRACE_OVERFLOW, | ||
| 16 | AUX_INFO0, | ||
| 17 | AUX_INFO1, | ||
| 18 | AUX_INFO2, | ||
| 19 | AUX_INFO3, | ||
| 20 | AUX_INFO4, | ||
| 21 | MAX_SCRATCH_REG, | ||
| 22 | }; | ||
| 23 | |||
| 12 | enum xe_survivability_type { | 24 | enum xe_survivability_type { |
| 13 | XE_SURVIVABILITY_TYPE_BOOT, | 25 | XE_SURVIVABILITY_TYPE_BOOT, |
| 14 | XE_SURVIVABILITY_TYPE_RUNTIME, | 26 | XE_SURVIVABILITY_TYPE_RUNTIME, |
| 15 | }; | 27 | }; |
| 16 | 28 | ||
| 17 | struct xe_survivability_info { | ||
| 18 | char name[NAME_MAX]; | ||
| 19 | u32 reg; | ||
| 20 | u32 value; | ||
| 21 | }; | ||
| 22 | |||
| 23 | /** | 29 | /** |
| 24 | * struct xe_survivability: Contains survivability mode information | 30 | * struct xe_survivability: Contains survivability mode information |
| 25 | */ | 31 | */ |
| 26 | struct xe_survivability { | 32 | struct xe_survivability { |
| 27 | /** @info: struct that holds survivability info from scratch registers */ | 33 | /** @info: survivability debug info */ |
| 28 | struct xe_survivability_info *info; | 34 | u32 info[MAX_SCRATCH_REG]; |
| 29 | 35 | ||
| 30 | /** @size: number of scratch registers */ | 36 | /** @size: number of scratch registers */ |
| 31 | u32 size; | 37 | u32 size; |
| @@ -38,6 +44,12 @@ struct xe_survivability { · 6 unmodified lines | |||
| 38 | 44 | ||
| 39 | /** @type: survivability type */ | 45 | /** @type: survivability type */ |
| 40 | enum xe_survivability_type type; | 46 | enum xe_survivability_type type; |
| 47 | |||
| 48 | /** @fdo_mode: indicates if FDO mode is enabled */ | ||
| 49 | bool fdo_mode; | ||
| 50 | |||
| 51 | /** @version: breadcrumb version of survivability mode */ | ||
| 52 | u8 version; | ||
| 41 | }; | 53 | }; |
| 42 | 54 | ||
| 43 | #endif /* _XE_SURVIVABILITY_MODE_TYPES_H_ */ | 55 | #endif /* _XE_SURVIVABILITY_MODE_TYPES_H_ */ |
| @@ -176,24 +176,13 @@ xe_svm_range_notifier_event_end(struct xe_vm *vm, struct drm_gpusvm_range *r, · 175 unmodified lines | |||
| 176 | mmu_range); | 176 | mmu_range); |
| 177 | } | 177 | } |
| 178 | 178 | ||
| 179 | static s64 xe_svm_stats_ktime_us_delta(ktime_t start) | ||
| 180 | { | ||
| 181 | return IS_ENABLED(CONFIG_DEBUG_FS) ? | ||
| 182 | ktime_us_delta(ktime_get(), start) : 0; | ||
| 183 | } | ||
| 184 | |||
| 185 | static void xe_svm_tlb_inval_us_stats_incr(struct xe_gt *gt, ktime_t start) | 179 | static void xe_svm_tlb_inval_us_stats_incr(struct xe_gt *gt, ktime_t start) |
| 186 | { | 180 | { |
| 187 | s64 us_delta = xe_svm_stats_ktime_us_delta(start); | 181 | s64 us_delta = xe_gt_stats_ktime_us_delta(start); |
| 188 | 182 | ||
| 189 | xe_gt_stats_incr(gt, XE_GT_STATS_ID_SVM_TLB_INVAL_US, us_delta); | 183 | xe_gt_stats_incr(gt, XE_GT_STATS_ID_SVM_TLB_INVAL_US, us_delta); |
| 190 | } | 184 | } |
| 191 | 185 | ||
| 192 | static ktime_t xe_svm_stats_ktime_get(void) | ||
| 193 | { | ||
| 194 | return IS_ENABLED(CONFIG_DEBUG_FS) ? ktime_get() : 0; | ||
| 195 | } | ||
| 196 | |||
| 197 | static void xe_svm_invalidate(struct drm_gpusvm *gpusvm, | 186 | static void xe_svm_invalidate(struct drm_gpusvm *gpusvm, |
| 198 | struct drm_gpusvm_notifier *notifier, | 187 | struct drm_gpusvm_notifier *notifier, |
| 199 | const struct mmu_notifier_range *mmu_range) | 188 | const struct mmu_notifier_range *mmu_range) |
| @@ -202,7 +191,7 @@ static void xe_svm_invalidate(struct drm_gpusvm *gpusvm, · 2 unmodified lines | |||
| 202 | struct xe_device *xe = vm->xe; | 191 | struct xe_device *xe = vm->xe; |
| 203 | struct drm_gpusvm_range *r, *first; | 192 | struct drm_gpusvm_range *r, *first; |
| 204 | struct xe_tile *tile; | 193 | struct xe_tile *tile; |
| 205 | ktime_t start = xe_svm_stats_ktime_get(); | 194 | ktime_t start = xe_gt_stats_ktime_get(); |
| 206 | u64 adj_start = mmu_range->start, adj_end = mmu_range->end; | 195 | u64 adj_start = mmu_range->start, adj_end = mmu_range->end; |
| 207 | u8 tile_mask = 0, id; | 196 | u8 tile_mask = 0, id; |
| 208 | long err; | 197 | long err; |
| @@ -285,19 +274,21 @@ static int __xe_svm_garbage_collector(struct xe_vm *vm, · 76 unmodified lines | |||
| 285 | return 0; | 274 | return 0; |
| 286 | } | 275 | } |
| 287 | 276 | ||
| 288 | static int xe_svm_range_set_default_attr(struct xe_vm *vm, u64 range_start, u64 range_end) | 277 | static void xe_vma_set_default_attributes(struct xe_vma *vma) |
| 278 | { | ||
| 279 | vma->attr.preferred_loc.devmem_fd = DRM_XE_PREFERRED_LOC_DEFAULT_DEVICE; | ||
| 280 | vma->attr.preferred_loc.migration_policy = DRM_XE_MIGRATE_ALL_PAGES; | ||
| 281 | vma->attr.pat_index = vma->attr.default_pat_index; | ||
| 282 | vma->attr.atomic_access = DRM_XE_ATOMIC_UNDEFINED; | ||
| 283 | } | ||
| 284 | |||
| 285 | static int xe_svm_range_set_default_attr(struct xe_vm *vm, u64 start, u64 end) | ||
| 289 | { | 286 | { |
| 290 | struct xe_vma *vma; | 287 | struct xe_vma *vma; |
| 291 | struct xe_vma_mem_attr default_attr = { | 288 | bool has_default_attr; |
| 292 | .preferred_loc = { | 289 | int err; |
| 293 | .devmem_fd = DRM_XE_PREFERRED_LOC_DEFAULT_DEVICE, | ||
| 294 | .migration_policy = DRM_XE_MIGRATE_ALL_PAGES, | ||
| 295 | }, | ||
| 296 | .atomic_access = DRM_XE_ATOMIC_UNDEFINED, | ||
| 297 | }; | ||
| 298 | int err = 0; | ||
| 299 | 290 | ||
| 300 | vma = xe_vm_find_vma_by_addr(vm, range_start); | 291 | vma = xe_vm_find_vma_by_addr(vm, start); |
| 301 | if (!vma) | 292 | if (!vma) |
| 302 | return -EINVAL; | 293 | return -EINVAL; |
| 303 | 294 | ||
| @@ -306,25 +297,30 @@ static int xe_svm_range_set_default_attr(struct xe_vm *vm, u64 range_start, u64 · 2 unmodified lines | |||
| 306 | return 0; | 297 | return 0; |
| 307 | } | 298 | } |
| 308 | 299 | ||
| 309 | if (xe_vma_has_default_mem_attrs(vma)) | ||
| 310 | return 0; | ||
| 311 | |||
| 312 | vm_dbg(&vm->xe->drm, "Existing VMA start=0x%016llx, vma_end=0x%016llx", | 300 | vm_dbg(&vm->xe->drm, "Existing VMA start=0x%016llx, vma_end=0x%016llx", |
| 313 | xe_vma_start(vma), xe_vma_end(vma)); | 301 | xe_vma_start(vma), xe_vma_end(vma)); |
| 314 | 302 | ||
| 315 | if (xe_vma_start(vma) == range_start && xe_vma_end(vma) == range_end) { | 303 | has_default_attr = xe_vma_has_default_mem_attrs(vma); |
| 316 | default_attr.pat_index = vma->attr.default_pat_index; | 304 | |
| 317 | default_attr.default_pat_index = vma->attr.default_pat_index; | 305 | if (has_default_attr) { |
| 318 | vma->attr = default_attr; | 306 | start = xe_vma_start(vma); |
| 319 | } else { | 307 | end = xe_vma_end(vma); |
| 320 | vm_dbg(&vm->xe->drm, "Split VMA start=0x%016llx, vma_end=0x%016llx", | 308 | } else if (xe_vma_start(vma) == start && xe_vma_end(vma) == end) { |
| 321 | range_start, range_end); | 309 | xe_vma_set_default_attributes(vma); |
| 322 | err = xe_vm_alloc_cpu_addr_mirror_vma(vm, range_start, range_end - range_start); | 310 | } |
| 323 | if (err) { | 311 | |
| 324 | drm_warn(&vm->xe->drm, "VMA SPLIT failed: %pe\n", ERR_PTR(err)); | 312 | xe_vm_find_cpu_addr_mirror_vma_range(vm, &start, &end); |
| 325 | xe_vm_kill(vm, true); | 313 | |
| 326 | return err; | 314 | if (xe_vma_start(vma) == start && xe_vma_end(vma) == end && has_default_attr) |
| 327 | } | 315 | return 0; |
| 316 | |||
| 317 | vm_dbg(&vm->xe->drm, "New VMA start=0x%016llx, vma_end=0x%016llx", start, end); | ||
| 318 | |||
| 319 | err = xe_vm_alloc_cpu_addr_mirror_vma(vm, start, end - start); | ||
| 320 | if (err) { | ||
| 321 | drm_warn(&vm->xe->drm, "New VMA MAP failed: %pe\n", ERR_PTR(err)); | ||
| 322 | xe_vm_kill(vm, true); | ||
| 323 | return err; | ||
| 328 | } | 324 | } |
| 329 | 325 | ||
| 330 | /* | 326 | /* |
| @@ -435,7 +431,7 @@ static void xe_svm_copy_us_stats_incr(struct xe_gt *gt, · 104 unmodified lines | |||
| 435 | unsigned long npages, | 431 | unsigned long npages, |
| 436 | ktime_t start) | 432 | ktime_t start) |
| 437 | { | 433 | { |
| 438 | s64 us_delta = xe_svm_stats_ktime_us_delta(start); | 434 | s64 us_delta = xe_gt_stats_ktime_us_delta(start); |
| 439 | 435 | ||
| 440 | if (dir == XE_SVM_COPY_TO_VRAM) { | 436 | if (dir == XE_SVM_COPY_TO_VRAM) { |
| 441 | switch (npages) { | 437 | switch (npages) { |
| @@ -487,7 +483,7 @@ static int xe_svm_copy(struct page **pages, · 45 unmodified lines | |||
| 487 | u64 vram_addr = XE_VRAM_ADDR_INVALID; | 483 | u64 vram_addr = XE_VRAM_ADDR_INVALID; |
| 488 | int err = 0, pos = 0; | 484 | int err = 0, pos = 0; |
| 489 | bool sram = dir == XE_SVM_COPY_TO_SRAM; | 485 | bool sram = dir == XE_SVM_COPY_TO_SRAM; |
| 490 | ktime_t start = xe_svm_stats_ktime_get(); | 486 | ktime_t start = xe_gt_stats_ktime_get(); |
| 491 | 487 | ||
| 492 | /* | 488 | /* |
| 493 | * This flow is complex: it locates physically contiguous device pages, | 489 | * This flow is complex: it locates physically contiguous device pages, |
| @@ -979,7 +975,7 @@ static void xe_svm_range_##elem##_us_stats_incr(struct xe_gt *gt, \ · 485 unmodified lines | |||
| 979 | struct xe_svm_range *range, \ | 975 | struct xe_svm_range *range, \ |
| 980 | ktime_t start) \ | 976 | ktime_t start) \ |
| 981 | { \ | 977 | { \ |
| 982 | s64 us_delta = xe_svm_stats_ktime_us_delta(start); \ | 978 | s64 us_delta = xe_gt_stats_ktime_us_delta(start); \ |
| 983 | \ | 979 | \ |
| 984 | switch (xe_svm_range_size(range)) { \ | 980 | switch (xe_svm_range_size(range)) { \ |
| 985 | case SZ_4K: \ | 981 | case SZ_4K: \ |
| @@ -1024,7 +1020,7 @@ static int __xe_svm_handle_pagefault(struct xe_vm *vm, struct xe_vma *vma, · 38 unmodified lines | |||
| 1024 | struct drm_pagemap *dpagemap; | 1020 | struct drm_pagemap *dpagemap; |
| 1025 | struct xe_tile *tile = gt_to_tile(gt); | 1021 | struct xe_tile *tile = gt_to_tile(gt); |
| 1026 | int migrate_try_count = ctx.devmem_only ? 3 : 1; | 1022 | int migrate_try_count = ctx.devmem_only ? 3 : 1; |
| 1027 | ktime_t start = xe_svm_stats_ktime_get(), bind_start, get_pages_start; | 1023 | ktime_t start = xe_gt_stats_ktime_get(), bind_start, get_pages_start; |
| 1028 | int err; | 1024 | int err; |
| 1029 | 1025 | ||
| 1030 | lockdep_assert_held_write(&vm->lock); | 1026 | lockdep_assert_held_write(&vm->lock); |
| @@ -1063,7 +1059,7 @@ retry: · 32 unmodified lines | |||
| 1063 | 1059 | ||
| 1064 | if (--migrate_try_count >= 0 && | 1060 | if (--migrate_try_count >= 0 && |
| 1065 | xe_svm_range_needs_migrate_to_vram(range, vma, !!dpagemap || ctx.devmem_only)) { | 1061 | xe_svm_range_needs_migrate_to_vram(range, vma, !!dpagemap || ctx.devmem_only)) { |
| 1066 | ktime_t migrate_start = xe_svm_stats_ktime_get(); | 1062 | ktime_t migrate_start = xe_gt_stats_ktime_get(); |
| 1067 | 1063 | ||
| 1068 | /* TODO : For multi-device dpagemap will be used to find the | 1064 | /* TODO : For multi-device dpagemap will be used to find the |
| 1069 | * remote tile and remote device. Will need to modify | 1065 | * remote tile and remote device. Will need to modify |
| @@ -1100,7 +1096,7 @@ retry: · 30 unmodified lines | |||
| 1100 | } | 1096 | } |
| 1101 | 1097 | ||
| 1102 | get_pages: | 1098 | get_pages: |
| 1103 | get_pages_start = xe_svm_stats_ktime_get(); | 1099 | get_pages_start = xe_gt_stats_ktime_get(); |
| 1104 | 1100 | ||
| 1105 | range_debug(range, "GET PAGES"); | 1101 | range_debug(range, "GET PAGES"); |
| 1106 | err = xe_svm_range_get_pages(vm, range, &ctx); | 1102 | err = xe_svm_range_get_pages(vm, range, &ctx); |
| @@ -1127,7 +1123,7 @@ get_pages: · 20 unmodified lines | |||
| 1127 | xe_svm_range_get_pages_us_stats_incr(gt, range, get_pages_start); | 1123 | xe_svm_range_get_pages_us_stats_incr(gt, range, get_pages_start); |
| 1128 | range_debug(range, "PAGE FAULT - BIND"); | 1124 | range_debug(range, "PAGE FAULT - BIND"); |
| 1129 | 1125 | ||
| 1130 | bind_start = xe_svm_stats_ktime_get(); | 1126 | bind_start = xe_gt_stats_ktime_get(); |
| 1131 | xe_validation_guard(&vctx, &vm->xe->val, &exec, (struct xe_val_flags) {}, err) { | 1127 | xe_validation_guard(&vctx, &vm->xe->val, &exec, (struct xe_val_flags) {}, err) { |
| 1132 | err = xe_vm_drm_exec_lock(vm, &exec); | 1128 | err = xe_vm_drm_exec_lock(vm, &exec); |
| 1133 | drm_exec_retry_on_contention(&exec); | 1129 | drm_exec_retry_on_contention(&exec); |
| @@ -228,6 +228,32 @@ int xe_sync_entry_add_deps(struct xe_sync_entry *sync, struct xe_sched_job *job) · 227 unmodified lines | |||
| 228 | return 0; | 228 | return 0; |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | /** | ||
| 232 | * xe_sync_entry_wait() - Wait on in-sync | ||
| 233 | * @sync: Sync object | ||
| 234 | * | ||
| 235 | * If the sync is in an in-sync, wait on the sync to signal. | ||
| 236 | * | ||
| 237 | * Return: 0 on success, -ERESTARTSYS on failure (interruption) | ||
| 238 | */ | ||
| 239 | int xe_sync_entry_wait(struct xe_sync_entry *sync) | ||
| 240 | { | ||
| 241 | return xe_sync_needs_wait(sync) ? | ||
| 242 | dma_fence_wait(sync->fence, true) : 0; | ||
| 243 | } | ||
| 244 | |||
| 245 | /** | ||
| 246 | * xe_sync_needs_wait() - Sync needs a wait (input dma-fence not signaled) | ||
| 247 | * @sync: Sync object | ||
| 248 | * | ||
| 249 | * Return: True if sync needs a wait, False otherwise | ||
| 250 | */ | ||
| 251 | bool xe_sync_needs_wait(struct xe_sync_entry *sync) | ||
| 252 | { | ||
| 253 | return sync->fence && | ||
| 254 | !test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &sync->fence->flags); | ||
| 255 | } | ||
| 256 | |||
| 231 | void xe_sync_entry_signal(struct xe_sync_entry *sync, struct dma_fence *fence) | 257 | void xe_sync_entry_signal(struct xe_sync_entry *sync, struct dma_fence *fence) |
| 232 | { | 258 | { |
| 233 | if (!(sync->flags & DRM_XE_SYNC_FLAG_SIGNAL)) | 259 | if (!(sync->flags & DRM_XE_SYNC_FLAG_SIGNAL)) |
| @@ -311,8 +337,11 @@ xe_sync_in_fence_get(struct xe_sync_entry *sync, int num_sync, · 77 unmodified lines | |||
| 311 | struct xe_tile *tile; | 337 | struct xe_tile *tile; |
| 312 | u8 id; | 338 | u8 id; |
| 313 | 339 | ||
| 314 | for_each_tile(tile, vm->xe, id) | 340 | for_each_tile(tile, vm->xe, id) { |
| 315 | num_fence += (1 + XE_MAX_GT_PER_TILE); | 341 | num_fence++; |
| 342 | for_each_tlb_inval(i) | ||
| 343 | num_fence++; | ||
| 344 | } | ||
| 316 | 345 | ||
| 317 | fences = kmalloc_array(num_fence, sizeof(*fences), | 346 | fences = kmalloc_array(num_fence, sizeof(*fences), |
| 318 | GFP_KERNEL); | 347 | GFP_KERNEL); |
| @@ -29,6 +29,8 @@ int xe_sync_entry_add_deps(struct xe_sync_entry *sync, · 28 unmodified lines | |||
| 29 | struct xe_sched_job *job); | 29 | struct xe_sched_job *job); |
| 30 | void xe_sync_entry_signal(struct xe_sync_entry *sync, | 30 | void xe_sync_entry_signal(struct xe_sync_entry *sync, |
| 31 | struct dma_fence *fence); | 31 | struct dma_fence *fence); |
| 32 | int xe_sync_entry_wait(struct xe_sync_entry *sync); | ||
| 33 | bool xe_sync_needs_wait(struct xe_sync_entry *sync); | ||
| 32 | void xe_sync_entry_cleanup(struct xe_sync_entry *sync); | 34 | void xe_sync_entry_cleanup(struct xe_sync_entry *sync); |
| 33 | struct dma_fence * | 35 | struct dma_fence * |
| 34 | xe_sync_in_fence_get(struct xe_sync_entry *sync, int num_sync, | 36 | xe_sync_in_fence_get(struct xe_sync_entry *sync, int num_sync, |
| @@ -209,6 +209,11 @@ int xe_tile_init(struct xe_tile *tile) · 208 unmodified lines | |||
| 209 | if (IS_ERR(tile->mem.kernel_bb_pool)) | 209 | if (IS_ERR(tile->mem.kernel_bb_pool)) |
| 210 | return PTR_ERR(tile->mem.kernel_bb_pool); | 210 | return PTR_ERR(tile->mem.kernel_bb_pool); |
| 211 | 211 | ||
| 212 | /* Optimistically anticipate at most 256 TLB fences with PRL */ | ||
| 213 | tile->mem.reclaim_pool = xe_sa_bo_manager_init(tile, SZ_1M, XE_PAGE_RECLAIM_LIST_MAX_SIZE); | ||
| 214 | if (IS_ERR(tile->mem.reclaim_pool)) | ||
| 215 | return PTR_ERR(tile->mem.reclaim_pool); | ||
| 216 | |||
| 212 | return 0; | 217 | return 0; |
| 213 | } | 218 | } |
| 214 | void xe_tile_migrate_wait(struct xe_tile *tile) | 219 | void xe_tile_migrate_wait(struct xe_tile *tile) |
| @@ -82,13 +82,9 @@ int xe_tile_debugfs_show_with_rpm(struct seq_file *m, void *data) · 81 unmodified lines | |||
| 82 | struct drm_info_node *node = m->private; | 82 | struct drm_info_node *node = m->private; |
| 83 | struct xe_tile *tile = node_to_tile(node); | 83 | struct xe_tile *tile = node_to_tile(node); |
| 84 | struct xe_device *xe = tile_to_xe(tile); | 84 | struct xe_device *xe = tile_to_xe(tile); |
| 85 | int ret; | ||
| 86 | 85 | ||
| 87 | xe_pm_runtime_get(xe); | 86 | guard(xe_pm_runtime)(xe); |
| 88 | ret = xe_tile_debugfs_simple_show(m, data); | 87 | return xe_tile_debugfs_simple_show(m, data); |
| 89 | xe_pm_runtime_put(xe); | ||
| 90 | |||
| 91 | return ret; | ||
| 92 | } | 88 | } |
| 93 | 89 | ||
| 94 | static int ggtt(struct xe_tile *tile, struct drm_printer *p) | 90 | static int ggtt(struct xe_tile *tile, struct drm_printer *p) |
| @@ -110,6 +106,13 @@ static const struct drm_info_list vf_safe_debugfs_list[] = { · 15 unmodified lines | |||
| 110 | { "sa_info", .show = xe_tile_debugfs_show_with_rpm, .data = sa_info }, | 106 | { "sa_info", .show = xe_tile_debugfs_show_with_rpm, .data = sa_info }, |
| 111 | }; | 107 | }; |
| 112 | 108 | ||
| 109 | static void tile_debugfs_create_vram_mm(struct xe_tile *tile) | ||
| 110 | { | ||
| 111 | if (tile->mem.vram) | ||
| 112 | ttm_resource_manager_create_debugfs(&tile->mem.vram->ttm.manager, tile->debugfs, | ||
| 113 | "vram_mm"); | ||
| 114 | } | ||
| 115 | |||
| 113 | /** | 116 | /** |
| 114 | * xe_tile_debugfs_register - Register tile's debugfs attributes | 117 | * xe_tile_debugfs_register - Register tile's debugfs attributes |
| 115 | * @tile: the &xe_tile to register | 118 | * @tile: the &xe_tile to register |
| @@ -139,4 +142,6 @@ void xe_tile_debugfs_register(struct xe_tile *tile) · 23 unmodified lines | |||
| 139 | drm_debugfs_create_files(vf_safe_debugfs_list, | 142 | drm_debugfs_create_files(vf_safe_debugfs_list, |
| 140 | ARRAY_SIZE(vf_safe_debugfs_list), | 143 | ARRAY_SIZE(vf_safe_debugfs_list), |
| 141 | tile->debugfs, minor); | 144 | tile->debugfs, minor); |
| 145 | |||
| 146 | tile_debugfs_create_vram_mm(tile); | ||
| 142 | } | 147 | } |
| @@ -141,12 +141,11 @@ static int NAME##_set(void *data, u64 val) \ · 140 unmodified lines | |||
| 141 | if (val > (TYPE)~0ull) \ | 141 | if (val > (TYPE)~0ull) \ |
| 142 | return -EOVERFLOW; \ | 142 | return -EOVERFLOW; \ |
| 143 | \ | 143 | \ |
| 144 | xe_pm_runtime_get(xe); \ | 144 | guard(xe_pm_runtime)(xe); \ |
| 145 | err = xe_sriov_pf_wait_ready(xe) ?: \ | 145 | err = xe_sriov_pf_wait_ready(xe) ?: \ |
| 146 | xe_gt_sriov_pf_config_set_##CONFIG(gt, vfid, val); \ | 146 | xe_gt_sriov_pf_config_set_##CONFIG(gt, vfid, val); \ |
| 147 | if (!err) \ | 147 | if (!err) \ |
| 148 | xe_sriov_pf_provision_set_custom_mode(xe); \ | 148 | xe_sriov_pf_provision_set_custom_mode(xe); \ |
| 149 | xe_pm_runtime_put(xe); \ | ||
| 150 | \ | 149 | \ |
| 151 | return err; \ | 150 | return err; \ |
| 152 | } \ | 151 | } \ |
| @@ -199,6 +199,20 @@ void xe_tlb_inval_reset(struct xe_tlb_inval *tlb_inval) · 198 unmodified lines | |||
| 199 | mutex_unlock(&tlb_inval->seqno_lock); | 199 | mutex_unlock(&tlb_inval->seqno_lock); |
| 200 | } | 200 | } |
| 201 | 201 | ||
| 202 | /** | ||
| 203 | * xe_tlb_inval_reset_timeout() - Reset TLB inval fence timeout | ||
| 204 | * @tlb_inval: TLB invalidation client | ||
| 205 | * | ||
| 206 | * Reset the TLB invalidation timeout timer. | ||
| 207 | */ | ||
| 208 | static void xe_tlb_inval_reset_timeout(struct xe_tlb_inval *tlb_inval) | ||
| 209 | { | ||
| 210 | lockdep_assert_held(&tlb_inval->pending_lock); | ||
| 211 | |||
| 212 | mod_delayed_work(system_wq, &tlb_inval->fence_tdr, | ||
| 213 | tlb_inval->ops->timeout_delay(tlb_inval)); | ||
| 214 | } | ||
| 215 | |||
| 202 | static bool xe_tlb_inval_seqno_past(struct xe_tlb_inval *tlb_inval, int seqno) | 216 | static bool xe_tlb_inval_seqno_past(struct xe_tlb_inval *tlb_inval, int seqno) |
| 203 | { | 217 | { |
| 204 | int seqno_recv = READ_ONCE(tlb_inval->seqno_recv); | 218 | int seqno_recv = READ_ONCE(tlb_inval->seqno_recv); |
| @@ -299,6 +313,7 @@ int xe_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval) · 94 unmodified lines | |||
| 299 | * @start: start address | 313 | * @start: start address |
| 300 | * @end: end address | 314 | * @end: end address |
| 301 | * @asid: address space id | 315 | * @asid: address space id |
| 316 | * @prl_sa: suballocation of page reclaim list if used, NULL indicates PPC flush | ||
| 302 | * | 317 | * |
| 303 | * Issue a range based TLB invalidation if supported, if not fallback to a full | 318 | * Issue a range based TLB invalidation if supported, if not fallback to a full |
| 304 | * TLB invalidation. Completion of TLB is asynchronous and caller can use | 319 | * TLB invalidation. Completion of TLB is asynchronous and caller can use |
| @@ -308,10 +323,10 @@ int xe_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval) · 3 unmodified lines | |||
| 308 | */ | 323 | */ |
| 309 | int xe_tlb_inval_range(struct xe_tlb_inval *tlb_inval, | 324 | int xe_tlb_inval_range(struct xe_tlb_inval *tlb_inval, |
| 310 | struct xe_tlb_inval_fence *fence, u64 start, u64 end, | 325 | struct xe_tlb_inval_fence *fence, u64 start, u64 end, |
| 311 | u32 asid) | 326 | u32 asid, struct drm_suballoc *prl_sa) |
| 312 | { | 327 | { |
| 313 | return xe_tlb_inval_issue(tlb_inval, fence, tlb_inval->ops->ppgtt, | 328 | return xe_tlb_inval_issue(tlb_inval, fence, tlb_inval->ops->ppgtt, |
| 314 | start, end, asid); | 329 | start, end, asid, prl_sa); |
| 315 | } | 330 | } |
| 316 | 331 | ||
| 317 | /** | 332 | /** |
| @@ -327,7 +342,7 @@ void xe_tlb_inval_vm(struct xe_tlb_inval *tlb_inval, struct xe_vm *vm) · 9 unmodified lines | |||
| 327 | u64 range = 1ull << vm->xe->info.va_bits; | 342 | u64 range = 1ull << vm->xe->info.va_bits; |
| 328 | 343 | ||
| 329 | xe_tlb_inval_fence_init(tlb_inval, &fence, true); | 344 | xe_tlb_inval_fence_init(tlb_inval, &fence, true); |
| 330 | xe_tlb_inval_range(tlb_inval, &fence, 0, range, vm->usm.asid); | 345 | xe_tlb_inval_range(tlb_inval, &fence, 0, range, vm->usm.asid, NULL); |
| 331 | xe_tlb_inval_fence_wait(&fence); | 346 | xe_tlb_inval_fence_wait(&fence); |
| 332 | } | 347 | } |
| 333 | 348 | ||
| @@ -360,6 +375,12 @@ void xe_tlb_inval_done_handler(struct xe_tlb_inval *tlb_inval, int seqno) · 26 unmodified lines | |||
| 360 | * process_g2h_msg(). | 375 | * process_g2h_msg(). |
| 361 | */ | 376 | */ |
| 362 | spin_lock_irqsave(&tlb_inval->pending_lock, flags); | 377 | spin_lock_irqsave(&tlb_inval->pending_lock, flags); |
| 378 | if (seqno == TLB_INVALIDATION_SEQNO_INVALID) { | ||
| 379 | xe_tlb_inval_reset_timeout(tlb_inval); | ||
| 380 | spin_unlock_irqrestore(&tlb_inval->pending_lock, flags); | ||
| 381 | return; | ||
| 382 | } | ||
| 383 | |||
| 363 | if (xe_tlb_inval_seqno_past(tlb_inval, seqno)) { | 384 | if (xe_tlb_inval_seqno_past(tlb_inval, seqno)) { |
| 364 | spin_unlock_irqrestore(&tlb_inval->pending_lock, flags); | 385 | spin_unlock_irqrestore(&tlb_inval->pending_lock, flags); |
| 365 | return; | 386 | return; |
| @@ -23,7 +23,7 @@ int xe_tlb_inval_ggtt(struct xe_tlb_inval *tlb_inval); · 22 unmodified lines | |||
| 23 | void xe_tlb_inval_vm(struct xe_tlb_inval *tlb_inval, struct xe_vm *vm); | 23 | void xe_tlb_inval_vm(struct xe_tlb_inval *tlb_inval, struct xe_vm *vm); |
| 24 | int xe_tlb_inval_range(struct xe_tlb_inval *tlb_inval, | 24 | int xe_tlb_inval_range(struct xe_tlb_inval *tlb_inval, |
| 25 | struct xe_tlb_inval_fence *fence, | 25 | struct xe_tlb_inval_fence *fence, |
| 26 | u64 start, u64 end, u32 asid); | 26 | u64 start, u64 end, u32 asid, struct drm_suballoc *prl_sa); |
| 27 | 27 | ||
| 28 | void xe_tlb_inval_fence_init(struct xe_tlb_inval *tlb_inval, | 28 | void xe_tlb_inval_fence_init(struct xe_tlb_inval *tlb_inval, |
| 29 | struct xe_tlb_inval_fence *fence, | 29 | struct xe_tlb_inval_fence *fence, |
| @@ -7,7 +7,9 @@ · 6 unmodified lines | |||
| 7 | #include "xe_dep_job_types.h" | 7 | #include "xe_dep_job_types.h" |
| 8 | #include "xe_dep_scheduler.h" | 8 | #include "xe_dep_scheduler.h" |
| 9 | #include "xe_exec_queue.h" | 9 | #include "xe_exec_queue.h" |
| 10 | #include "xe_gt_printk.h" | ||
| 10 | #include "xe_gt_types.h" | 11 | #include "xe_gt_types.h" |
| 12 | #include "xe_page_reclaim.h" | ||
| 11 | #include "xe_tlb_inval.h" | 13 | #include "xe_tlb_inval.h" |
| 12 | #include "xe_tlb_inval_job.h" | 14 | #include "xe_tlb_inval_job.h" |
| 13 | #include "xe_migrate.h" | 15 | #include "xe_migrate.h" |
| @@ -24,6 +26,8 @@ struct xe_tlb_inval_job { · 10 unmodified lines | |||
| 24 | struct xe_exec_queue *q; | 26 | struct xe_exec_queue *q; |
| 25 | /** @vm: VM which TLB invalidation is being issued for */ | 27 | /** @vm: VM which TLB invalidation is being issued for */ |
| 26 | struct xe_vm *vm; | 28 | struct xe_vm *vm; |
| 29 | /** @prl: Embedded copy of page reclaim list */ | ||
| 30 | struct xe_page_reclaim_list prl; | ||
| 27 | /** @refcount: ref count of this job */ | 31 | /** @refcount: ref count of this job */ |
| 28 | struct kref refcount; | 32 | struct kref refcount; |
| 29 | /** | 33 | /** |
| @@ -47,9 +51,16 @@ static struct dma_fence *xe_tlb_inval_job_run(struct xe_dep_job *dep_job) · 17 unmodified lines | |||
| 47 | container_of(dep_job, typeof(*job), dep); | 51 | container_of(dep_job, typeof(*job), dep); |
| 48 | struct xe_tlb_inval_fence *ifence = | 52 | struct xe_tlb_inval_fence *ifence = |
| 49 | container_of(job->fence, typeof(*ifence), base); | 53 | container_of(job->fence, typeof(*ifence), base); |
| 54 | struct drm_suballoc *prl_sa = NULL; | ||
| 55 | |||
| 56 | if (xe_page_reclaim_list_valid(&job->prl)) { | ||
| 57 | prl_sa = xe_page_reclaim_create_prl_bo(job->tlb_inval, &job->prl, ifence); | ||
| 58 | if (IS_ERR(prl_sa)) | ||
| 59 | prl_sa = NULL; /* Indicate fall back PPC flush with NULL */ | ||
| 60 | } | ||
| 50 | 61 | ||
| 51 | xe_tlb_inval_range(job->tlb_inval, ifence, job->start, | 62 | xe_tlb_inval_range(job->tlb_inval, ifence, job->start, |
| 52 | job->end, job->vm->usm.asid); | 63 | job->end, job->vm->usm.asid, prl_sa); |
| 53 | 64 | ||
| 54 | return job->fence; | 65 | return job->fence; |
| 55 | } | 66 | } |
| @@ -107,6 +118,7 @@ xe_tlb_inval_job_create(struct xe_exec_queue *q, struct xe_tlb_inval *tlb_inval, · 51 unmodified lines | |||
| 107 | job->start = start; | 118 | job->start = start; |
| 108 | job->end = end; | 119 | job->end = end; |
| 109 | job->fence_armed = false; | 120 | job->fence_armed = false; |
| 121 | xe_page_reclaim_list_init(&job->prl); | ||
| 110 | job->dep.ops = &dep_job_ops; | 122 | job->dep.ops = &dep_job_ops; |
| 111 | job->type = type; | 123 | job->type = type; |
| 112 | kref_init(&job->refcount); | 124 | kref_init(&job->refcount); |
| @@ -140,6 +152,25 @@ err_job: · 27 unmodified lines | |||
| 140 | return ERR_PTR(err); | 152 | return ERR_PTR(err); |
| 141 | } | 153 | } |
| 142 | 154 | ||
| 155 | /** | ||
| 156 | * xe_tlb_inval_job_add_page_reclaim() - Embed PRL into a TLB job | ||
| 157 | * @job: TLB invalidation job that may trigger reclamation | ||
| 158 | * @prl: Page reclaim list populated during unbind | ||
| 159 | * | ||
| 160 | * Copies @prl into the job and takes an extra reference to the entry page so | ||
| 161 | * ownership can transfer to the TLB fence when the job is pushed. | ||
| 162 | */ | ||
| 163 | void xe_tlb_inval_job_add_page_reclaim(struct xe_tlb_inval_job *job, | ||
| 164 | struct xe_page_reclaim_list *prl) | ||
| 165 | { | ||
| 166 | struct xe_device *xe = gt_to_xe(job->q->gt); | ||
| 167 | |||
| 168 | xe_gt_WARN_ON(job->q->gt, !xe->info.has_page_reclaim_hw_assist); | ||
| 169 | job->prl = *prl; | ||
| 170 | /* Pair with put in job_destroy */ | ||
| 171 | xe_page_reclaim_entries_get(job->prl.entries); | ||
| 172 | } | ||
| 173 | |||
| 143 | static void xe_tlb_inval_job_destroy(struct kref *ref) | 174 | static void xe_tlb_inval_job_destroy(struct kref *ref) |
| 144 | { | 175 | { |
| 145 | struct xe_tlb_inval_job *job = container_of(ref, typeof(*job), | 176 | struct xe_tlb_inval_job *job = container_of(ref, typeof(*job), |
| @@ -150,6 +181,9 @@ static void xe_tlb_inval_job_destroy(struct kref *ref) · 4 unmodified lines | |||
| 150 | struct xe_device *xe = gt_to_xe(q->gt); | 181 | struct xe_device *xe = gt_to_xe(q->gt); |
| 151 | struct xe_vm *vm = job->vm; | 182 | struct xe_vm *vm = job->vm; |
| 152 | 183 | ||
| 184 | /* BO creation retains a copy (if used), so no longer needed */ | ||
| 185 | xe_page_reclaim_entries_put(job->prl.entries); | ||
| 186 | |||
| 153 | if (!job->fence_armed) | 187 | if (!job->fence_armed) |
| 154 | kfree(ifence); | 188 | kfree(ifence); |
| 155 | else | 189 | else |
| @@ -12,6 +12,7 @@ struct dma_fence; · 11 unmodified lines | |||
| 12 | struct xe_dep_scheduler; | 12 | struct xe_dep_scheduler; |
| 13 | struct xe_exec_queue; | 13 | struct xe_exec_queue; |
| 14 | struct xe_migrate; | 14 | struct xe_migrate; |
| 15 | struct xe_page_reclaim_list; | ||
| 15 | struct xe_tlb_inval; | 16 | struct xe_tlb_inval; |
| 16 | struct xe_tlb_inval_job; | 17 | struct xe_tlb_inval_job; |
| 17 | struct xe_vm; | 18 | struct xe_vm; |
| @@ -21,6 +22,9 @@ xe_tlb_inval_job_create(struct xe_exec_queue *q, struct xe_tlb_inval *tlb_inval, · 3 unmodified lines | |||
| 21 | struct xe_dep_scheduler *dep_scheduler, | 22 | struct xe_dep_scheduler *dep_scheduler, |
| 22 | struct xe_vm *vm, u64 start, u64 end, int type); | 23 | struct xe_vm *vm, u64 start, u64 end, int type); |
| 23 | 24 | ||
| 25 | void xe_tlb_inval_job_add_page_reclaim(struct xe_tlb_inval_job *job, | ||
| 26 | struct xe_page_reclaim_list *prl); | ||
| 27 | |||
| 24 | int xe_tlb_inval_job_alloc_dep(struct xe_tlb_inval_job *job); | 28 | int xe_tlb_inval_job_alloc_dep(struct xe_tlb_inval_job *job); |
| 25 | 29 | ||
| 26 | struct dma_fence *xe_tlb_inval_job_push(struct xe_tlb_inval_job *job, | 30 | struct dma_fence *xe_tlb_inval_job_push(struct xe_tlb_inval_job *job, |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | #include <linux/workqueue.h> | 9 | #include <linux/workqueue.h> |
| 10 | #include <linux/dma-fence.h> | 10 | #include <linux/dma-fence.h> |
| 11 | 11 | ||
| 12 | struct drm_suballoc; | ||
| 12 | struct xe_tlb_inval; | 13 | struct xe_tlb_inval; |
| 13 | 14 | ||
| 14 | /** struct xe_tlb_inval_ops - TLB invalidation ops (backend) */ | 15 | /** struct xe_tlb_inval_ops - TLB invalidation ops (backend) */ |
| @@ -40,12 +41,13 @@ struct xe_tlb_inval_ops { · 25 unmodified lines | |||
| 40 | * @start: Start address | 41 | * @start: Start address |
| 41 | * @end: End address | 42 | * @end: End address |
| 42 | * @asid: Address space ID | 43 | * @asid: Address space ID |
| 44 | * @prl_sa: Suballocation for page reclaim list | ||
| 43 | * | 45 | * |
| 44 | * Return 0 on success, -ECANCELED if backend is mid-reset, error on | 46 | * Return 0 on success, -ECANCELED if backend is mid-reset, error on |
| 45 | * failure | 47 | * failure |
| 46 | */ | 48 | */ |
| 47 | int (*ppgtt)(struct xe_tlb_inval *tlb_inval, u32 seqno, u64 start, | 49 | int (*ppgtt)(struct xe_tlb_inval *tlb_inval, u32 seqno, u64 start, |
| 48 | u64 end, u32 asid); | 50 | u64 end, u32 asid, struct drm_suballoc *prl_sa); |
| 49 | 51 | ||
| 50 | /** | 52 | /** |
| 51 | * @initialized: Backend is initialized | 53 | * @initialized: Backend is initialized |
| @@ -80,6 +82,7 @@ struct xe_tlb_inval { · 28 unmodified lines | |||
| 80 | const struct xe_tlb_inval_ops *ops; | 82 | const struct xe_tlb_inval_ops *ops; |
| 81 | /** @tlb_inval.seqno: TLB invalidation seqno, protected by CT lock */ | 83 | /** @tlb_inval.seqno: TLB invalidation seqno, protected by CT lock */ |
| 82 | #define TLB_INVALIDATION_SEQNO_MAX 0x100000 | 84 | #define TLB_INVALIDATION_SEQNO_MAX 0x100000 |
| 85 | #define TLB_INVALIDATION_SEQNO_INVALID TLB_INVALIDATION_SEQNO_MAX | ||
| 83 | int seqno; | 86 | int seqno; |
| 84 | /** @tlb_invalidation.seqno_lock: protects @tlb_invalidation.seqno */ | 87 | /** @tlb_invalidation.seqno_lock: protects @tlb_invalidation.seqno */ |
| 85 | struct mutex seqno_lock; | 88 | struct mutex seqno_lock; |
| @@ -13,6 +13,7 @@ · 12 unmodified lines | |||
| 13 | #include <linux/types.h> | 13 | #include <linux/types.h> |
| 14 | 14 | ||
| 15 | #include "xe_exec_queue_types.h" | 15 | #include "xe_exec_queue_types.h" |
| 16 | #include "xe_exec_queue.h" | ||
| 16 | #include "xe_gpu_scheduler_types.h" | 17 | #include "xe_gpu_scheduler_types.h" |
| 17 | #include "xe_gt_types.h" | 18 | #include "xe_gt_types.h" |
| 18 | #include "xe_guc_exec_queue_types.h" | 19 | #include "xe_guc_exec_queue_types.h" |
| @@ -97,11 +98,51 @@ DECLARE_EVENT_CLASS(xe_exec_queue, · 78 unmodified lines | |||
| 97 | __entry->guc_state, __entry->flags) | 98 | __entry->guc_state, __entry->flags) |
| 98 | ); | 99 | ); |
| 99 | 100 | ||
| 101 | DECLARE_EVENT_CLASS(xe_exec_queue_multi_queue, | ||
| 102 | TP_PROTO(struct xe_exec_queue *q), | ||
| 103 | TP_ARGS(q), | ||
| 104 | |||
| 105 | TP_STRUCT__entry( | ||
| 106 | __string(dev, __dev_name_eq(q)) | ||
| 107 | __field(enum xe_engine_class, class) | ||
| 108 | __field(u32, logical_mask) | ||
| 109 | __field(u8, gt_id) | ||
| 110 | __field(u16, width) | ||
| 111 | __field(u32, guc_id) | ||
| 112 | __field(u32, guc_state) | ||
| 113 | __field(u32, flags) | ||
| 114 | __field(u32, primary) | ||
| 115 | ), | ||
| 116 | |||
| 117 | TP_fast_assign( | ||
| 118 | __assign_str(dev); | ||
| 119 | __entry->class = q->class; | ||
| 120 | __entry->logical_mask = q->logical_mask; | ||
| 121 | __entry->gt_id = q->gt->info.id; | ||
| 122 | __entry->width = q->width; | ||
| 123 | __entry->guc_id = q->guc->id; | ||
| 124 | __entry->guc_state = atomic_read(&q->guc->state); | ||
| 125 | __entry->flags = q->flags; | ||
| 126 | __entry->primary = xe_exec_queue_multi_queue_primary(q)->guc->id; | ||
| 127 | ), | ||
| 128 | |||
| 129 | TP_printk("dev=%s, %d:0x%x, gt=%d, width=%d guc_id=%d, guc_state=0x%x, flags=0x%x, primary=%d", | ||
| 130 | __get_str(dev), __entry->class, __entry->logical_mask, | ||
| 131 | __entry->gt_id, __entry->width, __entry->guc_id, | ||
| 132 | __entry->guc_state, __entry->flags, | ||
| 133 | __entry->primary) | ||
| 134 | ); | ||
| 135 | |||
| 100 | DEFINE_EVENT(xe_exec_queue, xe_exec_queue_create, | 136 | DEFINE_EVENT(xe_exec_queue, xe_exec_queue_create, |
| 101 | TP_PROTO(struct xe_exec_queue *q), | 137 | TP_PROTO(struct xe_exec_queue *q), |
| 102 | TP_ARGS(q) | 138 | TP_ARGS(q) |
| 103 | ); | 139 | ); |
| 104 | 140 | ||
| 141 | DEFINE_EVENT(xe_exec_queue_multi_queue, xe_exec_queue_create_multi_queue, | ||
| 142 | TP_PROTO(struct xe_exec_queue *q), | ||
| 143 | TP_ARGS(q) | ||
| 144 | ); | ||
| 145 | |||
| 105 | DEFINE_EVENT(xe_exec_queue, xe_exec_queue_supress_resume, | 146 | DEFINE_EVENT(xe_exec_queue, xe_exec_queue_supress_resume, |
| 106 | TP_PROTO(struct xe_exec_queue *q), | 147 | TP_PROTO(struct xe_exec_queue *q), |
| 107 | TP_ARGS(q) | 148 | TP_ARGS(q) |
| @@ -172,6 +213,11 @@ DEFINE_EVENT(xe_exec_queue, xe_exec_queue_memory_cat_error, · 64 unmodified lines | |||
| 172 | TP_ARGS(q) | 213 | TP_ARGS(q) |
| 173 | ); | 214 | ); |
| 174 | 215 | ||
| 216 | DEFINE_EVENT(xe_exec_queue, xe_exec_queue_cgp_context_error, | ||
| 217 | TP_PROTO(struct xe_exec_queue *q), | ||
| 218 | TP_ARGS(q) | ||
| 219 | ); | ||
| 220 | |||
| 175 | DEFINE_EVENT(xe_exec_queue, xe_exec_queue_stop, | 221 | DEFINE_EVENT(xe_exec_queue, xe_exec_queue_stop, |
| 176 | TP_PROTO(struct xe_exec_queue *q), | 222 | TP_PROTO(struct xe_exec_queue *q), |
| 177 | TP_ARGS(q) | 223 | TP_ARGS(q) |
| @@ -218,9 +218,12 @@ int xe_uc_load_hw(struct xe_uc *uc) · 217 unmodified lines | |||
| 218 | 218 | ||
| 219 | xe_guc_engine_activity_enable_stats(&uc->guc); | 219 | xe_guc_engine_activity_enable_stats(&uc->guc); |
| 220 | 220 | ||
| 221 | /* We don't fail the driver load if HuC fails to auth, but let's warn */ | 221 | /* We don't fail the driver load if HuC fails to auth */ |
| 222 | ret = xe_huc_auth(&uc->huc, XE_HUC_AUTH_VIA_GUC); | 222 | ret = xe_huc_auth(&uc->huc, XE_HUC_AUTH_VIA_GUC); |
| 223 | xe_gt_assert(uc_to_gt(uc), !ret); | 223 | if (ret) |
| 224 | xe_gt_err(uc_to_gt(uc), | ||
| 225 | "HuC authentication failed (%pe), continuing with no HuC\n", | ||
| 226 | ERR_PTR(ret)); | ||
| 224 | 227 | ||
| 225 | /* GSC load is async */ | 228 | /* GSC load is async */ |
| 226 | xe_gsc_load_start(&uc->gsc); | 229 | xe_gsc_load_start(&uc->gsc); |
| @@ -301,6 +304,34 @@ int xe_uc_suspend(struct xe_uc *uc) · 74 unmodified lines | |||
| 301 | return xe_guc_suspend(&uc->guc); | 304 | return xe_guc_suspend(&uc->guc); |
| 302 | } | 305 | } |
| 303 | 306 | ||
| 307 | /** | ||
| 308 | * xe_uc_runtime_suspend() - UC runtime suspend | ||
| 309 | * @uc: the UC object | ||
| 310 | * | ||
| 311 | * Runtime suspend all UCs. | ||
| 312 | */ | ||
| 313 | void xe_uc_runtime_suspend(struct xe_uc *uc) | ||
| 314 | { | ||
| 315 | if (!xe_device_uc_enabled(uc_to_xe(uc))) | ||
| 316 | return; | ||
| 317 | |||
| 318 | xe_guc_runtime_suspend(&uc->guc); | ||
| 319 | } | ||
| 320 | |||
| 321 | /** | ||
| 322 | * xe_uc_runtime_resume() - UC runtime resume | ||
| 323 | * @uc: the UC object | ||
| 324 | * | ||
| 325 | * Runtime resume all UCs. | ||
| 326 | */ | ||
| 327 | void xe_uc_runtime_resume(struct xe_uc *uc) | ||
| 328 | { | ||
| 329 | if (!xe_device_uc_enabled(uc_to_xe(uc))) | ||
| 330 | return; | ||
| 331 | |||
| 332 | xe_guc_runtime_resume(&uc->guc); | ||
| 333 | } | ||
| 334 | |||
| 304 | /** | 335 | /** |
| 305 | * xe_uc_declare_wedged() - Declare UC wedged | 336 | * xe_uc_declare_wedged() - Declare UC wedged |
| 306 | * @uc: the UC object | 337 | * @uc: the UC object |
| @@ -14,6 +14,8 @@ int xe_uc_init_post_hwconfig(struct xe_uc *uc); · 13 unmodified lines | |||
| 14 | int xe_uc_load_hw(struct xe_uc *uc); | 14 | int xe_uc_load_hw(struct xe_uc *uc); |
| 15 | void xe_uc_gucrc_disable(struct xe_uc *uc); | 15 | void xe_uc_gucrc_disable(struct xe_uc *uc); |
| 16 | int xe_uc_reset_prepare(struct xe_uc *uc); | 16 | int xe_uc_reset_prepare(struct xe_uc *uc); |
| 17 | void xe_uc_runtime_resume(struct xe_uc *uc); | ||
| 18 | void xe_uc_runtime_suspend(struct xe_uc *uc); | ||
| 17 | void xe_uc_stop_prepare(struct xe_uc *uc); | 19 | void xe_uc_stop_prepare(struct xe_uc *uc); |
| 18 | void xe_uc_stop(struct xe_uc *uc); | 20 | void xe_uc_stop(struct xe_uc *uc); |
| 19 | int xe_uc_start(struct xe_uc *uc); | 21 | int xe_uc_start(struct xe_uc *uc); |
| @@ -115,11 +115,11 @@ struct fw_blobs_by_type { · 114 unmodified lines | |||
| 115 | #define XE_GT_TYPE_ANY XE_GT_TYPE_UNINITIALIZED | 115 | #define XE_GT_TYPE_ANY XE_GT_TYPE_UNINITIALIZED |
| 116 | 116 | ||
| 117 | #define XE_GUC_FIRMWARE_DEFS(fw_def, mmp_ver, major_ver) \ | 117 | #define XE_GUC_FIRMWARE_DEFS(fw_def, mmp_ver, major_ver) \ |
| 118 | fw_def(PANTHERLAKE, GT_TYPE_ANY, major_ver(xe, guc, ptl, 70, 49, 4)) \ | 118 | fw_def(PANTHERLAKE, GT_TYPE_ANY, major_ver(xe, guc, ptl, 70, 54, 0)) \ |
| 119 | fw_def(BATTLEMAGE, GT_TYPE_ANY, major_ver(xe, guc, bmg, 70, 49, 4)) \ | 119 | fw_def(BATTLEMAGE, GT_TYPE_ANY, major_ver(xe, guc, bmg, 70, 54, 0)) \ |
| 120 | fw_def(LUNARLAKE, GT_TYPE_ANY, major_ver(xe, guc, lnl, 70, 45, 2)) \ | 120 | fw_def(LUNARLAKE, GT_TYPE_ANY, major_ver(xe, guc, lnl, 70, 53, 0)) \ |
| 121 | fw_def(METEORLAKE, GT_TYPE_ANY, major_ver(i915, guc, mtl, 70, 44, 1)) \ | 121 | fw_def(METEORLAKE, GT_TYPE_ANY, major_ver(i915, guc, mtl, 70, 53, 0)) \ |
| 122 | fw_def(DG2, GT_TYPE_ANY, major_ver(i915, guc, dg2, 70, 45, 2)) \ | 122 | fw_def(DG2, GT_TYPE_ANY, major_ver(i915, guc, dg2, 70, 53, 0)) \ |
| 123 | fw_def(DG1, GT_TYPE_ANY, major_ver(i915, guc, dg1, 70, 44, 1)) \ | 123 | fw_def(DG1, GT_TYPE_ANY, major_ver(i915, guc, dg1, 70, 44, 1)) \ |
| 124 | fw_def(ALDERLAKE_N, GT_TYPE_ANY, major_ver(i915, guc, tgl, 70, 44, 1)) \ | 124 | fw_def(ALDERLAKE_N, GT_TYPE_ANY, major_ver(i915, guc, tgl, 70, 44, 1)) \ |
| 125 | fw_def(ALDERLAKE_P, GT_TYPE_ANY, major_ver(i915, guc, adlp, 70, 44, 1)) \ | 125 | fw_def(ALDERLAKE_P, GT_TYPE_ANY, major_ver(i915, guc, adlp, 70, 44, 1)) \ |
| @@ -1509,9 +1509,9 @@ struct xe_vm *xe_vm_create(struct xe_device *xe, u32 flags, struct xe_file *xef) · 1508 unmodified lines | |||
| 1509 | 1509 | ||
| 1510 | INIT_LIST_HEAD(&vm->preempt.exec_queues); | 1510 | INIT_LIST_HEAD(&vm->preempt.exec_queues); |
| 1511 | if (flags & XE_VM_FLAG_FAULT_MODE) | 1511 | if (flags & XE_VM_FLAG_FAULT_MODE) |
| 1512 | vm->preempt.min_run_period_ms = 0; | 1512 | vm->preempt.min_run_period_ms = xe->min_run_period_pf_ms; |
| 1513 | else | 1513 | else |
| 1514 | vm->preempt.min_run_period_ms = 5; | 1514 | vm->preempt.min_run_period_ms = xe->min_run_period_lr_ms; |
| 1515 | 1515 | ||
| 1516 | for_each_tile(tile, xe, id) | 1516 | for_each_tile(tile, xe, id) |
| 1517 | xe_range_fence_tree_init(&vm->rftree[id]); | 1517 | xe_range_fence_tree_init(&vm->rftree[id]); |
| @@ -2236,6 +2236,7 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops, · 718 unmodified lines | |||
| 2236 | struct drm_gpuva_ops *ops; | 2236 | struct drm_gpuva_ops *ops; |
| 2237 | struct drm_gpuva_op *__op; | 2237 | struct drm_gpuva_op *__op; |
| 2238 | struct drm_gpuvm_bo *vm_bo; | 2238 | struct drm_gpuvm_bo *vm_bo; |
| 2239 | u64 range_start = addr; | ||
| 2239 | u64 range_end = addr + range; | 2240 | u64 range_end = addr + range; |
| 2240 | int err; | 2241 | int err; |
| 2241 | 2242 | ||
| @@ -2248,10 +2249,16 @@ vm_bind_ioctl_ops_create(struct xe_vm *vm, struct xe_vma_ops *vops, · 6 unmodified lines | |||
| 2248 | 2249 | ||
| 2249 | switch (operation) { | 2250 | switch (operation) { |
| 2250 | case DRM_XE_VM_BIND_OP_MAP: | 2251 | case DRM_XE_VM_BIND_OP_MAP: |
| 2252 | if (flags & DRM_XE_VM_BIND_FLAG_CPU_ADDR_MIRROR) { | ||
| 2253 | xe_vm_find_cpu_addr_mirror_vma_range(vm, &range_start, &range_end); | ||
| 2254 | vops->flags |= XE_VMA_OPS_FLAG_ALLOW_SVM_UNMAP; | ||
| 2255 | } | ||
| 2256 | |||
| 2257 | fallthrough; | ||
| 2251 | case DRM_XE_VM_BIND_OP_MAP_USERPTR: { | 2258 | case DRM_XE_VM_BIND_OP_MAP_USERPTR: { |
| 2252 | struct drm_gpuvm_map_req map_req = { | 2259 | struct drm_gpuvm_map_req map_req = { |
| 2253 | .map.va.addr = addr, | 2260 | .map.va.addr = range_start, |
| 2254 | .map.va.range = range, | 2261 | .map.va.range = range_end - range_start, |
| 2255 | .map.gem.obj = obj, | 2262 | .map.gem.obj = obj, |
| 2256 | .map.gem.offset = bo_offset_or_userptr, | 2263 | .map.gem.offset = bo_offset_or_userptr, |
| 2257 | }; | 2264 | }; |
| @@ -2451,8 +2458,17 @@ static struct xe_vma *new_vma(struct xe_vm *vm, struct drm_gpuva_op_map *op, · 193 unmodified lines | |||
| 2451 | if (IS_ERR(vma)) | 2458 | if (IS_ERR(vma)) |
| 2452 | return vma; | 2459 | return vma; |
| 2453 | 2460 | ||
| 2454 | if (xe_vma_is_userptr(vma)) | 2461 | if (xe_vma_is_userptr(vma)) { |
| 2455 | err = xe_vma_userptr_pin_pages(to_userptr_vma(vma)); | 2462 | err = xe_vma_userptr_pin_pages(to_userptr_vma(vma)); |
| 2463 | /* | ||
| 2464 | * -EBUSY has dedicated meaning that a user fence | ||
| 2465 | * attached to the VMA is busy, in practice | ||
| 2466 | * xe_vma_userptr_pin_pages can only fail with -EBUSY if | ||
| 2467 | * we are low on memory so convert this to -ENOMEM. | ||
| 2468 | */ | ||
| 2469 | if (err == -EBUSY) | ||
| 2470 | err = -ENOMEM; | ||
| 2471 | } | ||
| 2456 | } | 2472 | } |
| 2457 | if (err) { | 2473 | if (err) { |
| 2458 | prep_vma_destroy(vm, vma, false); | 2474 | prep_vma_destroy(vm, vma, false); |
| @@ -2727,7 +2743,8 @@ static int vm_bind_ioctl_ops_parse(struct xe_vm *vm, struct drm_gpuva_ops *ops, · 268 unmodified lines | |||
| 2727 | 2743 | ||
| 2728 | if (xe_vma_is_cpu_addr_mirror(vma) && | 2744 | if (xe_vma_is_cpu_addr_mirror(vma) && |
| 2729 | xe_svm_has_mapping(vm, xe_vma_start(vma), | 2745 | xe_svm_has_mapping(vm, xe_vma_start(vma), |
| 2730 | xe_vma_end(vma))) | 2746 | xe_vma_end(vma)) && |
| 2747 | !(vops->flags & XE_VMA_OPS_FLAG_ALLOW_SVM_UNMAP)) | ||
| 2731 | return -EBUSY; | 2748 | return -EBUSY; |
| 2732 | 2749 | ||
| 2733 | if (!xe_vma_is_cpu_addr_mirror(vma)) | 2750 | if (!xe_vma_is_cpu_addr_mirror(vma)) |
| @@ -3107,19 +3124,19 @@ static struct dma_fence *ops_execute(struct xe_vm *vm, · 373 unmodified lines | |||
| 3107 | struct dma_fence *fence = NULL; | 3124 | struct dma_fence *fence = NULL; |
| 3108 | struct dma_fence **fences = NULL; | 3125 | struct dma_fence **fences = NULL; |
| 3109 | struct dma_fence_array *cf = NULL; | 3126 | struct dma_fence_array *cf = NULL; |
| 3110 | int number_tiles = 0, current_fence = 0, n_fence = 0, err; | 3127 | int number_tiles = 0, current_fence = 0, n_fence = 0, err, i; |
| 3111 | u8 id; | 3128 | u8 id; |
| 3112 | 3129 | ||
| 3113 | number_tiles = vm_ops_setup_tile_args(vm, vops); | 3130 | number_tiles = vm_ops_setup_tile_args(vm, vops); |
| 3114 | if (number_tiles == 0) | 3131 | if (number_tiles == 0) |
| 3115 | return ERR_PTR(-ENODATA); | 3132 | return ERR_PTR(-ENODATA); |
| 3116 | 3133 | ||
| 3117 | if (vops->flags & XE_VMA_OPS_FLAG_SKIP_TLB_WAIT) { | 3134 | for_each_tile(tile, vm->xe, id) { |
| 3118 | for_each_tile(tile, vm->xe, id) | 3135 | ++n_fence; |
| 3119 | ++n_fence; | 3136 | |
| 3120 | } else { | 3137 | if (!(vops->flags & XE_VMA_OPS_FLAG_SKIP_TLB_WAIT)) |
| 3121 | for_each_tile(tile, vm->xe, id) | 3138 | for_each_tlb_inval(i) |
| 3122 | n_fence += (1 + XE_MAX_GT_PER_TILE); | 3139 | ++n_fence; |
| 3123 | } | 3140 | } |
| 3124 | 3141 | ||
| 3125 | fences = kmalloc_array(n_fence, sizeof(*fences), GFP_KERNEL); | 3142 | fences = kmalloc_array(n_fence, sizeof(*fences), GFP_KERNEL); |
| @@ -3149,7 +3166,6 @@ static struct dma_fence *ops_execute(struct xe_vm *vm, · 23 unmodified lines | |||
| 3149 | 3166 | ||
| 3150 | for_each_tile(tile, vm->xe, id) { | 3167 | for_each_tile(tile, vm->xe, id) { |
| 3151 | struct xe_exec_queue *q = vops->pt_update_ops[tile->id].q; | 3168 | struct xe_exec_queue *q = vops->pt_update_ops[tile->id].q; |
| 3152 | int i; | ||
| 3153 | 3169 | ||
| 3154 | fence = NULL; | 3170 | fence = NULL; |
| 3155 | if (!vops->pt_update_ops[id].num_ops) | 3171 | if (!vops->pt_update_ops[id].num_ops) |
| @@ -3214,7 +3230,8 @@ static void op_add_ufence(struct xe_vm *vm, struct xe_vma_op *op, · 58 unmodified lines | |||
| 3214 | { | 3230 | { |
| 3215 | switch (op->base.op) { | 3231 | switch (op->base.op) { |
| 3216 | case DRM_GPUVA_OP_MAP: | 3232 | case DRM_GPUVA_OP_MAP: |
| 3217 | vma_add_ufence(op->map.vma, ufence); | 3233 | if (!xe_vma_is_cpu_addr_mirror(op->map.vma)) |
| 3234 | vma_add_ufence(op->map.vma, ufence); | ||
| 3218 | break; | 3235 | break; |
| 3219 | case DRM_GPUVA_OP_REMAP: | 3236 | case DRM_GPUVA_OP_REMAP: |
| 3220 | if (op->remap.prev) | 3237 | if (op->remap.prev) |
| @@ -3490,6 +3507,10 @@ static int xe_vm_bind_ioctl_validate_bo(struct xe_device *xe, struct xe_bo *bo, · 269 unmodified lines | |||
| 3490 | { | 3507 | { |
| 3491 | u16 coh_mode; | 3508 | u16 coh_mode; |
| 3492 | 3509 | ||
| 3510 | if (XE_IOCTL_DBG(xe, (bo->flags & XE_BO_FLAG_NO_COMPRESSION) && | ||
| 3511 | xe_pat_index_get_comp_en(xe, pat_index))) | ||
| 3512 | return -EINVAL; | ||
| 3513 | |||
| 3493 | if (XE_IOCTL_DBG(xe, range > xe_bo_size(bo)) || | 3514 | if (XE_IOCTL_DBG(xe, range > xe_bo_size(bo)) || |
| 3494 | XE_IOCTL_DBG(xe, obj_offset > | 3515 | XE_IOCTL_DBG(xe, obj_offset > |
| 3495 | xe_bo_size(bo) - range)) { | 3516 | xe_bo_size(bo) - range)) { |
| @@ -3913,7 +3934,7 @@ int xe_vm_range_tilemask_tlb_inval(struct xe_vm *vm, u64 start, · 417 unmodified lines | |||
| 3913 | 3934 | ||
| 3914 | err = xe_tlb_inval_range(&tile->primary_gt->tlb_inval, | 3935 | err = xe_tlb_inval_range(&tile->primary_gt->tlb_inval, |
| 3915 | &fence[fence_id], start, end, | 3936 | &fence[fence_id], start, end, |
| 3916 | vm->usm.asid); | 3937 | vm->usm.asid, NULL); |
| 3917 | if (err) | 3938 | if (err) |
| 3918 | goto wait; | 3939 | goto wait; |
| 3919 | ++fence_id; | 3940 | ++fence_id; |
| @@ -3926,7 +3947,7 @@ int xe_vm_range_tilemask_tlb_inval(struct xe_vm *vm, u64 start, · 6 unmodified lines | |||
| 3926 | 3947 | ||
| 3927 | err = xe_tlb_inval_range(&tile->media_gt->tlb_inval, | 3948 | err = xe_tlb_inval_range(&tile->media_gt->tlb_inval, |
| 3928 | &fence[fence_id], start, end, | 3949 | &fence[fence_id], start, end, |
| 3929 | vm->usm.asid); | 3950 | vm->usm.asid, NULL); |
| 3930 | if (err) | 3951 | if (err) |
| 3931 | goto wait; | 3952 | goto wait; |
| 3932 | ++fence_id; | 3953 | ++fence_id; |
| @@ -4032,10 +4053,18 @@ int xe_vm_validate_protected(struct xe_vm *vm) · 99 unmodified lines | |||
| 4032 | } | 4053 | } |
| 4033 | 4054 | ||
| 4034 | struct xe_vm_snapshot { | 4055 | struct xe_vm_snapshot { |
| 4056 | int uapi_flags; | ||
| 4035 | unsigned long num_snaps; | 4057 | unsigned long num_snaps; |
| 4036 | struct { | 4058 | struct { |
| 4037 | u64 ofs, bo_ofs; | 4059 | u64 ofs, bo_ofs; |
| 4038 | unsigned long len; | 4060 | unsigned long len; |
| 4061 | #define XE_VM_SNAP_FLAG_USERPTR BIT(0) | ||
| 4062 | #define XE_VM_SNAP_FLAG_READ_ONLY BIT(1) | ||
| 4063 | #define XE_VM_SNAP_FLAG_IS_NULL BIT(2) | ||
| 4064 | unsigned long flags; | ||
| 4065 | int uapi_mem_region; | ||
| 4066 | int pat_index; | ||
| 4067 | int cpu_caching; | ||
| 4039 | struct xe_bo *bo; | 4068 | struct xe_bo *bo; |
| 4040 | void *data; | 4069 | void *data; |
| 4041 | struct mm_struct *mm; | 4070 | struct mm_struct *mm; |
| @@ -4064,6 +4093,13 @@ struct xe_vm_snapshot *xe_vm_snapshot_capture(struct xe_vm *vm) · 22 unmodified lines | |||
| 4064 | goto out_unlock; | 4093 | goto out_unlock; |
| 4065 | } | 4094 | } |
| 4066 | 4095 | ||
| 4096 | if (vm->flags & XE_VM_FLAG_FAULT_MODE) | ||
| 4097 | snap->uapi_flags |= DRM_XE_VM_CREATE_FLAG_FAULT_MODE; | ||
| 4098 | if (vm->flags & XE_VM_FLAG_LR_MODE) | ||
| 4099 | snap->uapi_flags |= DRM_XE_VM_CREATE_FLAG_LR_MODE; | ||
| 4100 | if (vm->flags & XE_VM_FLAG_SCRATCH_PAGE) | ||
| 4101 | snap->uapi_flags |= DRM_XE_VM_CREATE_FLAG_SCRATCH_PAGE; | ||
| 4102 | |||
| 4067 | snap->num_snaps = num_snaps; | 4103 | snap->num_snaps = num_snaps; |
| 4068 | i = 0; | 4104 | i = 0; |
| 4069 | drm_gpuvm_for_each_va(gpuva, &vm->gpuvm) { | 4105 | drm_gpuvm_for_each_va(gpuva, &vm->gpuvm) { |
| @@ -4076,9 +4112,25 @@ struct xe_vm_snapshot *xe_vm_snapshot_capture(struct xe_vm *vm) · 6 unmodified lines | |||
| 4076 | 4112 | ||
| 4077 | snap->snap[i].ofs = xe_vma_start(vma); | 4113 | snap->snap[i].ofs = xe_vma_start(vma); |
| 4078 | snap->snap[i].len = xe_vma_size(vma); | 4114 | snap->snap[i].len = xe_vma_size(vma); |
| 4115 | snap->snap[i].flags = xe_vma_read_only(vma) ? | ||
| 4116 | XE_VM_SNAP_FLAG_READ_ONLY : 0; | ||
| 4117 | snap->snap[i].pat_index = vma->attr.pat_index; | ||
| 4079 | if (bo) { | 4118 | if (bo) { |
| 4119 | snap->snap[i].cpu_caching = bo->cpu_caching; | ||
| 4080 | snap->snap[i].bo = xe_bo_get(bo); | 4120 | snap->snap[i].bo = xe_bo_get(bo); |
| 4081 | snap->snap[i].bo_ofs = xe_vma_bo_offset(vma); | 4121 | snap->snap[i].bo_ofs = xe_vma_bo_offset(vma); |
| 4122 | switch (bo->ttm.resource->mem_type) { | ||
| 4123 | case XE_PL_SYSTEM: | ||
| 4124 | case XE_PL_TT: | ||
| 4125 | snap->snap[i].uapi_mem_region = 0; | ||
| 4126 | break; | ||
| 4127 | case XE_PL_VRAM0: | ||
| 4128 | snap->snap[i].uapi_mem_region = 1; | ||
| 4129 | break; | ||
| 4130 | case XE_PL_VRAM1: | ||
| 4131 | snap->snap[i].uapi_mem_region = 2; | ||
| 4132 | break; | ||
| 4133 | } | ||
| 4082 | } else if (xe_vma_is_userptr(vma)) { | 4134 | } else if (xe_vma_is_userptr(vma)) { |
| 4083 | struct mm_struct *mm = | 4135 | struct mm_struct *mm = |
| 4084 | to_userptr_vma(vma)->userptr.notifier.mm; | 4136 | to_userptr_vma(vma)->userptr.notifier.mm; |
| @@ -4089,8 +4141,14 @@ struct xe_vm_snapshot *xe_vm_snapshot_capture(struct xe_vm *vm) · 4 unmodified lines | |||
| 4089 | snap->snap[i].data = ERR_PTR(-EFAULT); | 4141 | snap->snap[i].data = ERR_PTR(-EFAULT); |
| 4090 | 4142 | ||
| 4091 | snap->snap[i].bo_ofs = xe_vma_userptr(vma); | 4143 | snap->snap[i].bo_ofs = xe_vma_userptr(vma); |
| 4144 | snap->snap[i].flags |= XE_VM_SNAP_FLAG_USERPTR; | ||
| 4145 | snap->snap[i].uapi_mem_region = 0; | ||
| 4146 | } else if (xe_vma_is_null(vma)) { | ||
| 4147 | snap->snap[i].flags |= XE_VM_SNAP_FLAG_IS_NULL; | ||
| 4148 | snap->snap[i].uapi_mem_region = -1; | ||
| 4092 | } else { | 4149 | } else { |
| 4093 | snap->snap[i].data = ERR_PTR(-ENOENT); | 4150 | snap->snap[i].data = ERR_PTR(-ENOENT); |
| 4151 | snap->snap[i].uapi_mem_region = -1; | ||
| 4094 | } | 4152 | } |
| 4095 | i++; | 4153 | i++; |
| 4096 | } | 4154 | } |
| @@ -4109,7 +4167,8 @@ void xe_vm_snapshot_capture_delayed(struct xe_vm_snapshot *snap) · 12 unmodified lines | |||
| 4109 | struct xe_bo *bo = snap->snap[i].bo; | 4167 | struct xe_bo *bo = snap->snap[i].bo; |
| 4110 | int err; | 4168 | int err; |
| 4111 | 4169 | ||
| 4112 | if (IS_ERR(snap->snap[i].data)) | 4170 | if (IS_ERR(snap->snap[i].data) || |
| 4171 | snap->snap[i].flags & XE_VM_SNAP_FLAG_IS_NULL) | ||
| 4113 | continue; | 4172 | continue; |
| 4114 | 4173 | ||
| 4115 | snap->snap[i].data = kvmalloc(snap->snap[i].len, GFP_USER); | 4174 | snap->snap[i].data = kvmalloc(snap->snap[i].len, GFP_USER); |
| @@ -4155,15 +4214,32 @@ void xe_vm_snapshot_print(struct xe_vm_snapshot *snap, struct drm_printer *p) · 39 unmodified lines | |||
| 4155 | return; | 4214 | return; |
| 4156 | } | 4215 | } |
| 4157 | 4216 | ||
| 4217 | drm_printf(p, "VM.uapi_flags: 0x%x\n", snap->uapi_flags); | ||
| 4158 | for (i = 0; i < snap->num_snaps; i++) { | 4218 | for (i = 0; i < snap->num_snaps; i++) { |
| 4159 | drm_printf(p, "[%llx].length: 0x%lx\n", snap->snap[i].ofs, snap->snap[i].len); | 4219 | drm_printf(p, "[%llx].length: 0x%lx\n", snap->snap[i].ofs, snap->snap[i].len); |
| 4160 | 4220 | ||
| 4221 | drm_printf(p, "[%llx].properties: %s|%s|mem_region=0x%lx|pat_index=%d|cpu_caching=%d\n", | ||
| 4222 | snap->snap[i].ofs, | ||
| 4223 | snap->snap[i].flags & XE_VM_SNAP_FLAG_READ_ONLY ? | ||
| 4224 | "read_only" : "read_write", | ||
| 4225 | snap->snap[i].flags & XE_VM_SNAP_FLAG_IS_NULL ? | ||
| 4226 | "null_sparse" : | ||
| 4227 | snap->snap[i].flags & XE_VM_SNAP_FLAG_USERPTR ? | ||
| 4228 | "userptr" : "bo", | ||
| 4229 | snap->snap[i].uapi_mem_region == -1 ? 0 : | ||
| 4230 | BIT(snap->snap[i].uapi_mem_region), | ||
| 4231 | snap->snap[i].pat_index, | ||
| 4232 | snap->snap[i].cpu_caching); | ||
| 4233 | |||
| 4161 | if (IS_ERR(snap->snap[i].data)) { | 4234 | if (IS_ERR(snap->snap[i].data)) { |
| 4162 | drm_printf(p, "[%llx].error: %li\n", snap->snap[i].ofs, | 4235 | drm_printf(p, "[%llx].error: %li\n", snap->snap[i].ofs, |
| 4163 | PTR_ERR(snap->snap[i].data)); | 4236 | PTR_ERR(snap->snap[i].data)); |
| 4164 | continue; | 4237 | continue; |
| 4165 | } | 4238 | } |
| 4166 | 4239 | ||
| 4240 | if (snap->snap[i].flags & XE_VM_SNAP_FLAG_IS_NULL) | ||
| 4241 | continue; | ||
| 4242 | |||
| 4167 | drm_printf(p, "[%llx].data: ", snap->snap[i].ofs); | 4243 | drm_printf(p, "[%llx].data: ", snap->snap[i].ofs); |
| 4168 | 4244 | ||
| 4169 | for (j = 0; j < snap->snap[i].len; j += sizeof(u32)) { | 4245 | for (j = 0; j < snap->snap[i].len; j += sizeof(u32)) { |
| @@ -4317,6 +4393,8 @@ static int xe_vm_alloc_vma(struct xe_vm *vm, · 147 unmodified lines | |||
| 4317 | 4393 | ||
| 4318 | if (is_madvise) | 4394 | if (is_madvise) |
| 4319 | vops.flags |= XE_VMA_OPS_FLAG_MADVISE; | 4395 | vops.flags |= XE_VMA_OPS_FLAG_MADVISE; |
| 4396 | else | ||
| 4397 | vops.flags |= XE_VMA_OPS_FLAG_ALLOW_SVM_UNMAP; | ||
| 4320 | 4398 | ||
| 4321 | err = vm_bind_ioctl_ops_parse(vm, ops, &vops); | 4399 | err = vm_bind_ioctl_ops_parse(vm, ops, &vops); |
| 4322 | if (err) | 4400 | if (err) |
| @@ -4390,6 +4468,46 @@ int xe_vm_alloc_madvise_vma(struct xe_vm *vm, uint64_t start, uint64_t range) · 67 unmodified lines | |||
| 4390 | return xe_vm_alloc_vma(vm, &map_req, true); | 4468 | return xe_vm_alloc_vma(vm, &map_req, true); |
| 4391 | } | 4469 | } |
| 4392 | 4470 | ||
| 4471 | static bool is_cpu_addr_vma_with_default_attr(struct xe_vma *vma) | ||
| 4472 | { | ||
| 4473 | return vma && xe_vma_is_cpu_addr_mirror(vma) && | ||
| 4474 | xe_vma_has_default_mem_attrs(vma); | ||
| 4475 | } | ||
| 4476 | |||
| 4477 | /** | ||
| 4478 | * xe_vm_find_cpu_addr_mirror_vma_range - Extend a VMA range to include adjacent CPU-mirrored VMAs | ||
| 4479 | * @vm: VM to search within | ||
| 4480 | * @start: Input/output pointer to the starting address of the range | ||
| 4481 | * @end: Input/output pointer to the end address of the range | ||
| 4482 | * | ||
| 4483 | * Given a range defined by @start and @range, this function checks the VMAs | ||
| 4484 | * immediately before and after the range. If those neighboring VMAs are | ||
| 4485 | * CPU-address-mirrored and have default memory attributes, the function | ||
| 4486 | * updates @start and @range to include them. This extended range can then | ||
| 4487 | * be used for merging or other operations that require a unified VMA. | ||
| 4488 | * | ||
| 4489 | * The function does not perform the merge itself; it only computes the | ||
| 4490 | * mergeable boundaries. | ||
| 4491 | */ | ||
| 4492 | void xe_vm_find_cpu_addr_mirror_vma_range(struct xe_vm *vm, u64 *start, u64 *end) | ||
| 4493 | { | ||
| 4494 | struct xe_vma *prev, *next; | ||
| 4495 | |||
| 4496 | lockdep_assert_held(&vm->lock); | ||
| 4497 | |||
| 4498 | if (*start >= SZ_4K) { | ||
| 4499 | prev = xe_vm_find_vma_by_addr(vm, *start - SZ_4K); | ||
| 4500 | if (is_cpu_addr_vma_with_default_attr(prev)) | ||
| 4501 | *start = xe_vma_start(prev); | ||
| 4502 | } | ||
| 4503 | |||
| 4504 | if (*end < vm->size) { | ||
| 4505 | next = xe_vm_find_vma_by_addr(vm, *end + 1); | ||
| 4506 | if (is_cpu_addr_vma_with_default_attr(next)) | ||
| 4507 | *end = xe_vma_end(next); | ||
| 4508 | } | ||
| 4509 | } | ||
| 4510 | |||
| 4393 | /** | 4511 | /** |
| 4394 | * xe_vm_alloc_cpu_addr_mirror_vma - Allocate CPU addr mirror vma | 4512 | * xe_vm_alloc_cpu_addr_mirror_vma - Allocate CPU addr mirror vma |
| 4395 | * @vm: Pointer to the xe_vm structure | 4513 | * @vm: Pointer to the xe_vm structure |
| @@ -68,6 +68,9 @@ xe_vm_find_overlapping_vma(struct xe_vm *vm, u64 start, u64 range); · 67 unmodified lines | |||
| 68 | 68 | ||
| 69 | bool xe_vma_has_default_mem_attrs(struct xe_vma *vma); | 69 | bool xe_vma_has_default_mem_attrs(struct xe_vma *vma); |
| 70 | 70 | ||
| 71 | void xe_vm_find_cpu_addr_mirror_vma_range(struct xe_vm *vm, | ||
| 72 | u64 *start, | ||
| 73 | u64 *end); | ||
| 71 | /** | 74 | /** |
| 72 | * xe_vm_has_scratch() - Whether the vm is configured for scratch PTEs | 75 | * xe_vm_has_scratch() - Whether the vm is configured for scratch PTEs |
| 73 | * @vm: The vm | 76 | * @vm: The vm |
| @@ -467,6 +467,7 @@ struct xe_vma_ops { · 466 unmodified lines | |||
| 467 | #define XE_VMA_OPS_FLAG_MADVISE BIT(1) | 467 | #define XE_VMA_OPS_FLAG_MADVISE BIT(1) |
| 468 | #define XE_VMA_OPS_ARRAY_OF_BINDS BIT(2) | 468 | #define XE_VMA_OPS_ARRAY_OF_BINDS BIT(2) |
| 469 | #define XE_VMA_OPS_FLAG_SKIP_TLB_WAIT BIT(3) | 469 | #define XE_VMA_OPS_FLAG_SKIP_TLB_WAIT BIT(3) |
| 470 | #define XE_VMA_OPS_FLAG_ALLOW_SVM_UNMAP BIT(4) | ||
| 470 | u32 flags; | 471 | u32 flags; |
| 471 | #ifdef TEST_VM_OPS_ERROR | 472 | #ifdef TEST_VM_OPS_ERROR |
| 472 | /** @inject_error: inject error to test error handling */ | 473 | /** @inject_error: inject error to test error handling */ |
| @@ -156,12 +156,11 @@ static int determine_lmem_bar_size(struct xe_device *xe, struct xe_vram_region * · 155 unmodified lines | |||
| 156 | static int get_flat_ccs_offset(struct xe_gt *gt, u64 tile_size, u64 *poffset) | 156 | static int get_flat_ccs_offset(struct xe_gt *gt, u64 tile_size, u64 *poffset) |
| 157 | { | 157 | { |
| 158 | struct xe_device *xe = gt_to_xe(gt); | 158 | struct xe_device *xe = gt_to_xe(gt); |
| 159 | unsigned int fw_ref; | ||
| 160 | u64 offset; | 159 | u64 offset; |
| 161 | u32 reg; | 160 | u32 reg; |
| 162 | 161 | ||
| 163 | fw_ref = xe_force_wake_get(gt_to_fw(gt), XE_FW_GT); | 162 | CLASS(xe_force_wake, fw_ref)(gt_to_fw(gt), XE_FW_GT); |
| 164 | if (!fw_ref) | 163 | if (!fw_ref.domains) |
| 165 | return -ETIMEDOUT; | 164 | return -ETIMEDOUT; |
| 166 | 165 | ||
| 167 | if (GRAPHICS_VER(xe) >= 20) { | 166 | if (GRAPHICS_VER(xe) >= 20) { |
| @@ -193,7 +192,6 @@ static int get_flat_ccs_offset(struct xe_gt *gt, u64 tile_size, u64 *poffset) · 25 unmodified lines | |||
| 193 | offset = (u64)REG_FIELD_GET(XEHP_FLAT_CCS_PTR, reg) * SZ_64K; | 192 | offset = (u64)REG_FIELD_GET(XEHP_FLAT_CCS_PTR, reg) * SZ_64K; |
| 194 | } | 193 | } |
| 195 | 194 | ||
| 196 | xe_force_wake_put(gt_to_fw(gt), fw_ref); | ||
| 197 | *poffset = offset; | 195 | *poffset = offset; |
| 198 | 196 | ||
| 199 | return 0; | 197 | return 0; |
| @@ -15,6 +15,7 @@ · 14 unmodified lines | |||
| 15 | 15 | ||
| 16 | #include "regs/xe_engine_regs.h" | 16 | #include "regs/xe_engine_regs.h" |
| 17 | #include "regs/xe_gt_regs.h" | 17 | #include "regs/xe_gt_regs.h" |
| 18 | #include "regs/xe_guc_regs.h" | ||
| 18 | #include "regs/xe_regs.h" | 19 | #include "regs/xe_regs.h" |
| 19 | #include "xe_device_types.h" | 20 | #include "xe_device_types.h" |
| 20 | #include "xe_force_wake.h" | 21 | #include "xe_force_wake.h" |
| @@ -216,20 +217,6 @@ static const struct xe_rtp_entry_sr gt_was[] = { · 195 unmodified lines | |||
| 216 | XE_RTP_ACTIONS(SET(XELPMP_SQCNT1, ENFORCE_RAR)) | 217 | XE_RTP_ACTIONS(SET(XELPMP_SQCNT1, ENFORCE_RAR)) |
| 217 | }, | 218 | }, |
| 218 | 219 | ||
| 219 | /* Xe2_LPG */ | ||
| 220 | |||
| 221 | { XE_RTP_NAME("16020975621"), | ||
| 222 | XE_RTP_RULES(GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0)), | ||
| 223 | XE_RTP_ACTIONS(SET(XEHP_SLICE_UNIT_LEVEL_CLKGATE, SBEUNIT_CLKGATE_DIS)) | ||
| 224 | }, | ||
| 225 | { XE_RTP_NAME("14018157293"), | ||
| 226 | XE_RTP_RULES(GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0)), | ||
| 227 | XE_RTP_ACTIONS(SET(XEHPC_L3CLOS_MASK(0), ~0), | ||
| 228 | SET(XEHPC_L3CLOS_MASK(1), ~0), | ||
| 229 | SET(XEHPC_L3CLOS_MASK(2), ~0), | ||
| 230 | SET(XEHPC_L3CLOS_MASK(3), ~0)) | ||
| 231 | }, | ||
| 232 | |||
| 233 | /* Xe2_LPM */ | 220 | /* Xe2_LPM */ |
| 234 | 221 | ||
| 235 | { XE_RTP_NAME("14017421178"), | 222 | { XE_RTP_NAME("14017421178"), |
| @@ -315,6 +302,10 @@ static const struct xe_rtp_entry_sr gt_was[] = { · 79 unmodified lines | |||
| 315 | XE_RTP_ACTIONS(SET(VDBOX_CGCTL3F10(0), RAMDFTUNIT_CLKGATE_DIS)), | 302 | XE_RTP_ACTIONS(SET(VDBOX_CGCTL3F10(0), RAMDFTUNIT_CLKGATE_DIS)), |
| 316 | XE_RTP_ENTRY_FLAG(FOREACH_ENGINE), | 303 | XE_RTP_ENTRY_FLAG(FOREACH_ENGINE), |
| 317 | }, | 304 | }, |
| 305 | { XE_RTP_NAME("16028005424"), | ||
| 306 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3005)), | ||
| 307 | XE_RTP_ACTIONS(SET(GUC_INTR_CHICKEN, DISABLE_SIGNALING_ENGINES)) | ||
| 308 | }, | ||
| 318 | }; | 309 | }; |
| 319 | 310 | ||
| 320 | static const struct xe_rtp_entry_sr engine_was[] = { | 311 | static const struct xe_rtp_entry_sr engine_was[] = { |
| @@ -504,11 +495,6 @@ static const struct xe_rtp_entry_sr engine_was[] = { · 183 unmodified lines | |||
| 504 | XE_RTP_RULES(GRAPHICS_VERSION(2004), FUNC(xe_rtp_match_first_render_or_compute)), | 495 | XE_RTP_RULES(GRAPHICS_VERSION(2004), FUNC(xe_rtp_match_first_render_or_compute)), |
| 505 | XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, XE2_ALLOC_DPA_STARVE_FIX_DIS)) | 496 | XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, XE2_ALLOC_DPA_STARVE_FIX_DIS)) |
| 506 | }, | 497 | }, |
| 507 | { XE_RTP_NAME("14018957109"), | ||
| 508 | XE_RTP_RULES(GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0), | ||
| 509 | FUNC(xe_rtp_match_first_render_or_compute)), | ||
| 510 | XE_RTP_ACTIONS(SET(HALF_SLICE_CHICKEN5, DISABLE_SAMPLE_G_PERFORMANCE)) | ||
| 511 | }, | ||
| 512 | { XE_RTP_NAME("14020338487"), | 498 | { XE_RTP_NAME("14020338487"), |
| 513 | XE_RTP_RULES(GRAPHICS_VERSION(2004), FUNC(xe_rtp_match_first_render_or_compute)), | 499 | XE_RTP_RULES(GRAPHICS_VERSION(2004), FUNC(xe_rtp_match_first_render_or_compute)), |
| 514 | XE_RTP_ACTIONS(SET(ROW_CHICKEN3, XE2_EUPEND_CHK_FLUSH_DIS)) | 500 | XE_RTP_ACTIONS(SET(ROW_CHICKEN3, XE2_EUPEND_CHK_FLUSH_DIS)) |
| @@ -518,11 +504,6 @@ static const struct xe_rtp_entry_sr engine_was[] = { · 3 unmodified lines | |||
| 518 | FUNC(xe_rtp_match_first_render_or_compute)), | 504 | FUNC(xe_rtp_match_first_render_or_compute)), |
| 519 | XE_RTP_ACTIONS(SET(ROW_CHICKEN4, DISABLE_TDL_PUSH)) | 505 | XE_RTP_ACTIONS(SET(ROW_CHICKEN4, DISABLE_TDL_PUSH)) |
| 520 | }, | 506 | }, |
| 521 | { XE_RTP_NAME("14019322943"), | ||
| 522 | XE_RTP_RULES(GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0), | ||
| 523 | FUNC(xe_rtp_match_first_render_or_compute)), | ||
| 524 | XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0, TGM_WRITE_EOM_FORCE)) | ||
| 525 | }, | ||
| 526 | { XE_RTP_NAME("14018471104"), | 507 | { XE_RTP_NAME("14018471104"), |
| 527 | XE_RTP_RULES(GRAPHICS_VERSION(2004), FUNC(xe_rtp_match_first_render_or_compute)), | 508 | XE_RTP_RULES(GRAPHICS_VERSION(2004), FUNC(xe_rtp_match_first_render_or_compute)), |
| 528 | XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, ENABLE_SMP_LD_RENDER_SURFACE_CONTROL)) | 509 | XE_RTP_ACTIONS(SET(LSC_CHICKEN_BIT_0_UDW, ENABLE_SMP_LD_RENDER_SURFACE_CONTROL)) |
| @@ -693,7 +674,7 @@ static const struct xe_rtp_entry_sr engine_was[] = { · 164 unmodified lines | |||
| 693 | XE_RTP_ACTIONS(SET(HALF_SLICE_CHICKEN7, CLEAR_OPTIMIZATION_DISABLE)) | 674 | XE_RTP_ACTIONS(SET(HALF_SLICE_CHICKEN7, CLEAR_OPTIMIZATION_DISABLE)) |
| 694 | }, | 675 | }, |
| 695 | { XE_RTP_NAME("18041344222"), | 676 | { XE_RTP_NAME("18041344222"), |
| 696 | XE_RTP_RULES(GRAPHICS_VERSION_RANGE(3000, 3001), | 677 | XE_RTP_RULES(GRAPHICS_VERSION(3000), |
| 697 | FUNC(xe_rtp_match_first_render_or_compute), | 678 | FUNC(xe_rtp_match_first_render_or_compute), |
| 698 | FUNC(xe_rtp_match_not_sriov_vf), | 679 | FUNC(xe_rtp_match_not_sriov_vf), |
| 699 | FUNC(xe_rtp_match_gt_has_discontiguous_dss_groups)), | 680 | FUNC(xe_rtp_match_gt_has_discontiguous_dss_groups)), |
| @@ -799,17 +780,6 @@ static const struct xe_rtp_entry_sr lrc_was[] = { · 99 unmodified lines | |||
| 799 | 780 | ||
| 800 | /* Xe2_LPG */ | 781 | /* Xe2_LPG */ |
| 801 | 782 | ||
| 802 | { XE_RTP_NAME("16020518922"), | ||
| 803 | XE_RTP_RULES(GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0), | ||
| 804 | ENGINE_CLASS(RENDER)), | ||
| 805 | XE_RTP_ACTIONS(SET(FF_MODE, | ||
| 806 | DIS_TE_AUTOSTRIP | | ||
| 807 | DIS_MESH_PARTIAL_AUTOSTRIP | | ||
| 808 | DIS_MESH_AUTOSTRIP), | ||
| 809 | SET(VFLSKPD, | ||
| 810 | DIS_PARTIAL_AUTOSTRIP | | ||
| 811 | DIS_AUTOSTRIP)) | ||
| 812 | }, | ||
| 813 | { XE_RTP_NAME("14019386621"), | 783 | { XE_RTP_NAME("14019386621"), |
| 814 | XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), | 784 | XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), |
| 815 | XE_RTP_ACTIONS(SET(VF_SCRATCHPAD, XE2_VFG_TED_CREDIT_INTERFACE_DISABLE)) | 785 | XE_RTP_ACTIONS(SET(VF_SCRATCHPAD, XE2_VFG_TED_CREDIT_INTERFACE_DISABLE)) |
| @@ -818,20 +788,10 @@ static const struct xe_rtp_entry_sr lrc_was[] = { · 2 unmodified lines | |||
| 818 | XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), | 788 | XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), |
| 819 | XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) | 789 | XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FD_END_COLLECT)) |
| 820 | }, | 790 | }, |
| 821 | { XE_RTP_NAME("14020013138"), | ||
| 822 | XE_RTP_RULES(GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0), | ||
| 823 | ENGINE_CLASS(RENDER)), | ||
| 824 | XE_RTP_ACTIONS(SET(WM_CHICKEN3, HIZ_PLANE_COMPRESSION_DIS)) | ||
| 825 | }, | ||
| 826 | { XE_RTP_NAME("14019988906"), | 791 | { XE_RTP_NAME("14019988906"), |
| 827 | XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), | 792 | XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), |
| 828 | XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD)) | 793 | XE_RTP_ACTIONS(SET(XEHP_PSS_CHICKEN, FLSH_IGNORES_PSD)) |
| 829 | }, | 794 | }, |
| 830 | { XE_RTP_NAME("16020183090"), | ||
| 831 | XE_RTP_RULES(GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0), | ||
| 832 | ENGINE_CLASS(RENDER)), | ||
| 833 | XE_RTP_ACTIONS(SET(INSTPM(RENDER_RING_BASE), ENABLE_SEMAPHORE_POLL_BIT)) | ||
| 834 | }, | ||
| 835 | { XE_RTP_NAME("18033852989"), | 795 | { XE_RTP_NAME("18033852989"), |
| 836 | XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), | 796 | XE_RTP_RULES(GRAPHICS_VERSION(2004), ENGINE_CLASS(RENDER)), |
| 837 | XE_RTP_ACTIONS(SET(COMMON_SLICE_CHICKEN1, DISABLE_BOTTOM_CLIP_RECTANGLE_TEST)) | 797 | XE_RTP_ACTIONS(SET(COMMON_SLICE_CHICKEN1, DISABLE_BOTTOM_CLIP_RECTANGLE_TEST)) |
| @@ -16,15 +16,11 @@ · 15 unmodified lines | |||
| 16 | 16017236439 PLATFORM(PVC) | 16 | 16017236439 PLATFORM(PVC) |
| 17 | 14019821291 MEDIA_VERSION_RANGE(1300, 2000) | 17 | 14019821291 MEDIA_VERSION_RANGE(1300, 2000) |
| 18 | 14015076503 MEDIA_VERSION(1300) | 18 | 14015076503 MEDIA_VERSION(1300) |
| 19 | 16020292621 GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0) | 19 | 14018913170 GRAPHICS_VERSION_RANGE(1270, 1274) |
| 20 | 14018913170 GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0) | ||
| 21 | MEDIA_VERSION(2000), GRAPHICS_STEP(A0, A1) | ||
| 22 | GRAPHICS_VERSION_RANGE(1270, 1274) | ||
| 23 | MEDIA_VERSION(1300) | 20 | MEDIA_VERSION(1300) |
| 24 | PLATFORM(DG2) | 21 | PLATFORM(DG2) |
| 25 | 14018094691 GRAPHICS_VERSION_RANGE(2001, 2002) | 22 | 14018094691 GRAPHICS_VERSION_RANGE(2001, 2002) |
| 26 | GRAPHICS_VERSION(2004) | 23 | GRAPHICS_VERSION(2004) |
| 27 | 14019882105 GRAPHICS_VERSION(2004), GRAPHICS_STEP(A0, B0) | ||
| 28 | 18024947630 GRAPHICS_VERSION(2001) | 24 | 18024947630 GRAPHICS_VERSION(2001) |
| 29 | GRAPHICS_VERSION(2004) | 25 | GRAPHICS_VERSION(2004) |
| 30 | MEDIA_VERSION(2000) | 26 | MEDIA_VERSION(2000) |
| @@ -106,6 +106,7 @@ extern "C" { · 105 unmodified lines | |||
| 106 | #define DRM_XE_OBSERVATION 0x0b | 106 | #define DRM_XE_OBSERVATION 0x0b |
| 107 | #define DRM_XE_MADVISE 0x0c | 107 | #define DRM_XE_MADVISE 0x0c |
| 108 | #define DRM_XE_VM_QUERY_MEM_RANGE_ATTRS 0x0d | 108 | #define DRM_XE_VM_QUERY_MEM_RANGE_ATTRS 0x0d |
| 109 | #define DRM_XE_EXEC_QUEUE_SET_PROPERTY 0x0e | ||
| 109 | 110 | ||
| 110 | /* Must be kept compact -- no holes */ | 111 | /* Must be kept compact -- no holes */ |
| 111 | 112 | ||
| @@ -123,6 +124,7 @@ extern "C" { · 11 unmodified lines | |||
| 123 | #define DRM_IOCTL_XE_OBSERVATION DRM_IOW(DRM_COMMAND_BASE + DRM_XE_OBSERVATION, struct drm_xe_observation_param) | 124 | #define DRM_IOCTL_XE_OBSERVATION DRM_IOW(DRM_COMMAND_BASE + DRM_XE_OBSERVATION, struct drm_xe_observation_param) |
| 124 | #define DRM_IOCTL_XE_MADVISE DRM_IOW(DRM_COMMAND_BASE + DRM_XE_MADVISE, struct drm_xe_madvise) | 125 | #define DRM_IOCTL_XE_MADVISE DRM_IOW(DRM_COMMAND_BASE + DRM_XE_MADVISE, struct drm_xe_madvise) |
| 125 | #define DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_VM_QUERY_MEM_RANGE_ATTRS, struct drm_xe_vm_query_mem_range_attr) | 126 | #define DRM_IOCTL_XE_VM_QUERY_MEM_RANGE_ATTRS DRM_IOWR(DRM_COMMAND_BASE + DRM_XE_VM_QUERY_MEM_RANGE_ATTRS, struct drm_xe_vm_query_mem_range_attr) |
| 127 | #define DRM_IOCTL_XE_EXEC_QUEUE_SET_PROPERTY DRM_IOW(DRM_COMMAND_BASE + DRM_XE_EXEC_QUEUE_SET_PROPERTY, struct drm_xe_exec_queue_set_property) | ||
| 126 | 128 | ||
| 127 | /** | 129 | /** |
| 128 | * DOC: Xe IOCTL Extensions | 130 | * DOC: Xe IOCTL Extensions |
| @@ -210,8 +212,12 @@ struct drm_xe_ext_set_property { · 81 unmodified lines | |||
| 210 | /** @pad: MBZ */ | 212 | /** @pad: MBZ */ |
| 211 | __u32 pad; | 213 | __u32 pad; |
| 212 | 214 | ||
| 213 | /** @value: property value */ | 215 | union { |
| 214 | __u64 value; | 216 | /** @value: property value */ |
| 217 | __u64 value; | ||
| 218 | /** @ptr: pointer to user value */ | ||
| 219 | __u64 ptr; | ||
| 220 | }; | ||
| 215 | 221 | ||
| 216 | /** @reserved: Reserved */ | 222 | /** @reserved: Reserved */ |
| 217 | __u64 reserved[2]; | 223 | __u64 reserved[2]; |
| @@ -403,6 +409,9 @@ struct drm_xe_query_mem_regions { · 185 unmodified lines | |||
| 403 | * has low latency hint support | 409 | * has low latency hint support |
| 404 | * - %DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR - Flag is set if the | 410 | * - %DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR - Flag is set if the |
| 405 | * device has CPU address mirroring support | 411 | * device has CPU address mirroring support |
| 412 | * - %DRM_XE_QUERY_CONFIG_FLAG_HAS_NO_COMPRESSION_HINT - Flag is set if the | ||
| 413 | * device supports the userspace hint %DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION. | ||
| 414 | * This is exposed only on Xe2+. | ||
| 406 | * - %DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT - Minimal memory alignment | 415 | * - %DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT - Minimal memory alignment |
| 407 | * required by this device, typically SZ_4K or SZ_64K | 416 | * required by this device, typically SZ_4K or SZ_64K |
| 408 | * - %DRM_XE_QUERY_CONFIG_VA_BITS - Maximum bits of a virtual address | 417 | * - %DRM_XE_QUERY_CONFIG_VA_BITS - Maximum bits of a virtual address |
| @@ -421,6 +430,7 @@ struct drm_xe_query_config { · 12 unmodified lines | |||
| 421 | #define DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM (1 << 0) | 430 | #define DRM_XE_QUERY_CONFIG_FLAG_HAS_VRAM (1 << 0) |
| 422 | #define DRM_XE_QUERY_CONFIG_FLAG_HAS_LOW_LATENCY (1 << 1) | 431 | #define DRM_XE_QUERY_CONFIG_FLAG_HAS_LOW_LATENCY (1 << 1) |
| 423 | #define DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR (1 << 2) | 432 | #define DRM_XE_QUERY_CONFIG_FLAG_HAS_CPU_ADDR_MIRROR (1 << 2) |
| 433 | #define DRM_XE_QUERY_CONFIG_FLAG_HAS_NO_COMPRESSION_HINT (1 << 3) | ||
| 424 | #define DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT 2 | 434 | #define DRM_XE_QUERY_CONFIG_MIN_ALIGNMENT 2 |
| 425 | #define DRM_XE_QUERY_CONFIG_VA_BITS 3 | 435 | #define DRM_XE_QUERY_CONFIG_VA_BITS 3 |
| 426 | #define DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY 4 | 436 | #define DRM_XE_QUERY_CONFIG_MAX_EXEC_QUEUE_PRIORITY 4 |
| @@ -791,6 +801,17 @@ struct drm_xe_device_query { · 364 unmodified lines | |||
| 791 | * need to use VRAM for display surfaces, therefore the kernel requires | 801 | * need to use VRAM for display surfaces, therefore the kernel requires |
| 792 | * setting this flag for such objects, otherwise an error is thrown on | 802 | * setting this flag for such objects, otherwise an error is thrown on |
| 793 | * small-bar systems. | 803 | * small-bar systems. |
| 804 | * - %DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION - Allows userspace to | ||
| 805 | * hint that compression (CCS) should be disabled for the buffer being | ||
| 806 | * created. This can avoid unnecessary memory operations and CCS state | ||
| 807 | * management. | ||
| 808 | * On pre-Xe2 platforms, this flag is currently rejected as compression | ||
| 809 | * control is not supported via PAT index. On Xe2+ platforms, compression | ||
| 810 | * is controlled via PAT entries. If this flag is set, the driver will reject | ||
| 811 | * any VM bind that requests a PAT index enabling compression for this BO. | ||
| 812 | * Note: On dGPU platforms, there is currently no change in behavior with | ||
| 813 | * this flag, but future improvements may leverage it. The current benefit is | ||
| 814 | * primarily applicable to iGPU platforms. | ||
| 794 | * | 815 | * |
| 795 | * @cpu_caching supports the following values: | 816 | * @cpu_caching supports the following values: |
| 796 | * - %DRM_XE_GEM_CPU_CACHING_WB - Allocate the pages with write-back | 817 | * - %DRM_XE_GEM_CPU_CACHING_WB - Allocate the pages with write-back |
| @@ -837,6 +858,7 @@ struct drm_xe_gem_create { · 40 unmodified lines | |||
| 837 | #define DRM_XE_GEM_CREATE_FLAG_DEFER_BACKING (1 << 0) | 858 | #define DRM_XE_GEM_CREATE_FLAG_DEFER_BACKING (1 << 0) |
| 838 | #define DRM_XE_GEM_CREATE_FLAG_SCANOUT (1 << 1) | 859 | #define DRM_XE_GEM_CREATE_FLAG_SCANOUT (1 << 1) |
| 839 | #define DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM (1 << 2) | 860 | #define DRM_XE_GEM_CREATE_FLAG_NEEDS_VISIBLE_VRAM (1 << 2) |
| 861 | #define DRM_XE_GEM_CREATE_FLAG_NO_COMPRESSION (1 << 3) | ||
| 840 | /** | 862 | /** |
| 841 | * @flags: Flags, currently a mask of memory instances of where BO can | 863 | * @flags: Flags, currently a mask of memory instances of where BO can |
| 842 | * be placed | 864 | * be placed |
| @@ -1252,6 +1274,20 @@ struct drm_xe_vm_bind { · 409 unmodified lines | |||
| 1252 | * Given that going into a power-saving state kills PXP HWDRM sessions, | 1274 | * Given that going into a power-saving state kills PXP HWDRM sessions, |
| 1253 | * runtime PM will be blocked while queues of this type are alive. | 1275 | * runtime PM will be blocked while queues of this type are alive. |
| 1254 | * All PXP queues will be killed if a PXP invalidation event occurs. | 1276 | * All PXP queues will be killed if a PXP invalidation event occurs. |
| 1277 | * - %DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP - Create a multi-queue group | ||
| 1278 | * or add secondary queues to a multi-queue group. | ||
| 1279 | * If the extension's 'value' field has %DRM_XE_MULTI_GROUP_CREATE flag set, | ||
| 1280 | * then a new multi-queue group is created with this queue as the primary queue | ||
| 1281 | * (Q0). Otherwise, the queue gets added to the multi-queue group whose primary | ||
| 1282 | * queue's exec_queue_id is specified in the lower 32 bits of the 'value' field. | ||
| 1283 | * If the extension's 'value' field has %DRM_XE_MULTI_GROUP_KEEP_ACTIVE flag | ||
| 1284 | * set, then the multi-queue group is kept active after the primary queue is | ||
| 1285 | * destroyed. | ||
| 1286 | * All the other non-relevant bits of extension's 'value' field while adding the | ||
| 1287 | * primary or the secondary queues of the group must be set to 0. | ||
| 1288 | * - %DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY - Set the queue | ||
| 1289 | * priority within the multi-queue group. Current valid priority values are 0–2 | ||
| 1290 | * (default is 1), with higher values indicating higher priority. | ||
| 1255 | * | 1291 | * |
| 1256 | * The example below shows how to use @drm_xe_exec_queue_create to create | 1292 | * The example below shows how to use @drm_xe_exec_queue_create to create |
| 1257 | * a simple exec_queue (no parallel submission) of class | 1293 | * a simple exec_queue (no parallel submission) of class |
| @@ -1292,6 +1328,11 @@ struct drm_xe_exec_queue_create { · 34 unmodified lines | |||
| 1292 | #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY 0 | 1328 | #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_PRIORITY 0 |
| 1293 | #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE 1 | 1329 | #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_TIMESLICE 1 |
| 1294 | #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE 2 | 1330 | #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_PXP_TYPE 2 |
| 1331 | #define DRM_XE_EXEC_QUEUE_SET_HANG_REPLAY_STATE 3 | ||
| 1332 | #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_GROUP 4 | ||
| 1333 | #define DRM_XE_MULTI_GROUP_CREATE (1ull << 63) | ||
| 1334 | #define DRM_XE_MULTI_GROUP_KEEP_ACTIVE (1ull << 62) | ||
| 1335 | #define DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY 5 | ||
| 1295 | /** @extensions: Pointer to the first extension struct, if any */ | 1336 | /** @extensions: Pointer to the first extension struct, if any */ |
| 1296 | __u64 extensions; | 1337 | __u64 extensions; |
| 1297 | 1338 | ||
| @@ -1655,6 +1696,9 @@ enum drm_xe_oa_unit_type { · 357 unmodified lines | |||
| 1655 | 1696 | ||
| 1656 | /** @DRM_XE_OA_UNIT_TYPE_OAM_SAG: OAM_SAG OA unit */ | 1697 | /** @DRM_XE_OA_UNIT_TYPE_OAM_SAG: OAM_SAG OA unit */ |
| 1657 | DRM_XE_OA_UNIT_TYPE_OAM_SAG, | 1698 | DRM_XE_OA_UNIT_TYPE_OAM_SAG, |
| 1699 | |||
| 1700 | /** @DRM_XE_OA_UNIT_TYPE_MERT: MERT OA unit */ | ||
| 1701 | DRM_XE_OA_UNIT_TYPE_MERT, | ||
| 1658 | }; | 1702 | }; |
| 1659 | 1703 | ||
| 1660 | /** | 1704 | /** |
| @@ -1677,12 +1721,19 @@ struct drm_xe_oa_unit { · 16 unmodified lines | |||
| 1677 | #define DRM_XE_OA_CAPS_OA_BUFFER_SIZE (1 << 2) | 1721 | #define DRM_XE_OA_CAPS_OA_BUFFER_SIZE (1 << 2) |
| 1678 | #define DRM_XE_OA_CAPS_WAIT_NUM_REPORTS (1 << 3) | 1722 | #define DRM_XE_OA_CAPS_WAIT_NUM_REPORTS (1 << 3) |
| 1679 | #define DRM_XE_OA_CAPS_OAM (1 << 4) | 1723 | #define DRM_XE_OA_CAPS_OAM (1 << 4) |
| 1724 | #define DRM_XE_OA_CAPS_OA_UNIT_GT_ID (1 << 5) | ||
| 1680 | 1725 | ||
| 1681 | /** @oa_timestamp_freq: OA timestamp freq */ | 1726 | /** @oa_timestamp_freq: OA timestamp freq */ |
| 1682 | __u64 oa_timestamp_freq; | 1727 | __u64 oa_timestamp_freq; |
| 1683 | 1728 | ||
| 1729 | /** @gt_id: gt id for this OA unit */ | ||
| 1730 | __u16 gt_id; | ||
| 1731 | |||
| 1732 | /** @reserved1: MBZ */ | ||
| 1733 | __u16 reserved1[3]; | ||
| 1734 | |||
| 1684 | /** @reserved: MBZ */ | 1735 | /** @reserved: MBZ */ |
| 1685 | __u64 reserved[4]; | 1736 | __u64 reserved[3]; |
| 1686 | 1737 | ||
| 1687 | /** @num_engines: number of engines in @eci array */ | 1738 | /** @num_engines: number of engines in @eci array */ |
| 1688 | __u64 num_engines; | 1739 | __u64 num_engines; |
| @@ -2274,6 +2325,30 @@ struct drm_xe_vm_query_mem_range_attr { · 585 unmodified lines | |||
| 2274 | 2325 | ||
| 2275 | }; | 2326 | }; |
| 2276 | 2327 | ||
| 2328 | /** | ||
| 2329 | * struct drm_xe_exec_queue_set_property - exec queue set property | ||
| 2330 | * | ||
| 2331 | * Sets execution queue properties dynamically. | ||
| 2332 | * Currently only %DRM_XE_EXEC_QUEUE_SET_PROPERTY_MULTI_QUEUE_PRIORITY | ||
| 2333 | * property can be dynamically set. | ||
| 2334 | */ | ||
| 2335 | struct drm_xe_exec_queue_set_property { | ||
| 2336 | /** @extensions: Pointer to the first extension struct, if any */ | ||
| 2337 | __u64 extensions; | ||
| 2338 | |||
| 2339 | /** @exec_queue_id: Exec queue ID */ | ||
| 2340 | __u32 exec_queue_id; | ||
| 2341 | |||
| 2342 | /** @property: property to set */ | ||
| 2343 | __u32 property; | ||
| 2344 | |||
| 2345 | /** @value: property value */ | ||
| 2346 | __u64 value; | ||
| 2347 | |||
| 2348 | /** @reserved: Reserved */ | ||
| 2349 | __u64 reserved[2]; | ||
| 2350 | }; | ||
| 2351 | |||
| 2277 | #if defined(__cplusplus) | 2352 | #if defined(__cplusplus) |
| 2278 | } | 2353 | } |
| 2279 | #endif | 2354 | #endif |