PTL will limit access to specific registers. Instead of silently
dropping these attempts, log them in dmesg for reference. Also add a
dev_debug option to show what pasid/addr/packet type failed.

Signed-off-by: Kent Russell <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c       | 34 +++++++++
 .../gpu/drm/amd/amdkfd/kfd_int_process_v9.c   | 76 +++++++++++++++++++
 drivers/gpu/drm/amd/amdkfd/soc15_int.h        |  1 +
 3 files changed, 111 insertions(+)

diff --git a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c 
b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
index 3572eb9b5758..1ce8313e3c26 100644
--- a/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
+++ b/drivers/gpu/drm/amd/amdgpu/gfx_v9_4_3.c
@@ -171,6 +171,7 @@ static int gfx_v9_4_3_get_cu_info(struct amdgpu_device 
*adev,
                                struct amdgpu_cu_info *cu_info);
 static void gfx_v9_4_3_xcc_set_safe_mode(struct amdgpu_device *adev, int 
xcc_id);
 static void gfx_v9_4_3_xcc_unset_safe_mode(struct amdgpu_device *adev, int 
xcc_id);
+static void gfx_v9_4_3_enable_ptl_skip_interrupt(struct amdgpu_device *adev);
 
 static void gfx_v9_4_3_kiq_set_resources(struct amdgpu_ring *kiq_ring,
                                uint64_t queue_mask)
@@ -2661,6 +2662,7 @@ static int gfx_v9_4_3_early_init(struct amdgpu_ip_block 
*ip_block)
 static int gfx_v9_4_3_late_init(struct amdgpu_ip_block *ip_block)
 {
        struct amdgpu_device *adev = ip_block->adev;
+       struct amdgpu_ptl *ptl = &adev->psp.ptl;
 
        if (adev->gfx.ras &&
            adev->gfx.ras->enable_watchdog_timer)
@@ -2668,6 +2670,10 @@ static int gfx_v9_4_3_late_init(struct amdgpu_ip_block 
*ip_block)
 
        gfx_v9_4_3_ptl_hw_init(adev);
 
+       /* Enable PTL register skip notifications if PTL is supported */
+       if (ptl->hw_supported_state == AMDGPU_PTL_HW_SUPPORTED)
+               gfx_v9_4_3_enable_ptl_skip_interrupt(adev);
+
        return 0;
 }
 
@@ -3327,6 +3333,34 @@ static int gfx_v9_4_3_set_bad_op_fault_state(struct 
amdgpu_device *adev,
        return 0;
 }
 
+/*
+ * Enable GENERIC1 interrupt (bit 30) for PTL register skip notifications.
+ * When FW skips a privileged register access due to PTL, it signals via
+ * GENERIC1 and KFD receives interrupt source 177 with skip details.
+ */
+static void gfx_v9_4_3_enable_ptl_skip_interrupt(struct amdgpu_device *adev)
+{
+       u32 mec_int_cntl_reg, mec_int_cntl;
+       int i, j, k, num_xcc;
+
+       num_xcc = NUM_XCC(adev->gfx.xcc_mask);
+       for (i = 0; i < num_xcc; i++) {
+               for (j = 0; j < adev->gfx.mec.num_mec; j++) {
+                       for (k = 0; k < adev->gfx.mec.num_pipe_per_mec; k++) {
+                               mec_int_cntl_reg = 
gfx_v9_4_3_get_cpc_int_cntl(adev, i, j + 1, k);
+
+                               if (mec_int_cntl_reg) {
+                                       mec_int_cntl = 
RREG32_XCC(mec_int_cntl_reg, i);
+                                       mec_int_cntl = 
REG_SET_FIELD(mec_int_cntl,
+                                                       CP_ME1_PIPE0_INT_CNTL,
+                                                       GENERIC1_INT_ENABLE, 1);
+                                       WREG32_XCC(mec_int_cntl_reg, 
mec_int_cntl, i);
+                               }
+                       }
+               }
+       }
+}
+
 static int gfx_v9_4_3_set_priv_inst_fault_state(struct amdgpu_device *adev,
                                              struct amdgpu_irq_src *source,
                                              unsigned type,
diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c 
b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
index e241ad7d55df..8dee8c43824d 100644
--- a/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
+++ b/drivers/gpu/drm/amd/amdkfd/kfd_int_process_v9.c
@@ -123,6 +123,28 @@ enum SQ_INTERRUPT_ERROR_TYPE {
 #define KFD_SQ_INT_DATA__ERR_TYPE_MASK 0xF00000
 #define KFD_SQ_INT_DATA__ERR_TYPE__SHIFT 20
 
+/*
+ * PTL (Peak TOPS Limiter) register skip notification.
+ * When FW skips a privileged register access, it sends interrupt 177
+ * with GENERIC1 and provides packet type info in CPC_INT_CNTX_ID[31:28].
+ */
+#define CPC_PTL_PACKET_TYPE_SET_UCONFIG_REG    1
+#define CPC_PTL_PACKET_TYPE_SET_SH_REG         2
+#define CPC_PTL_PACKET_TYPE_COPY_DATA_READ     3
+#define CPC_PTL_PACKET_TYPE_COPY_DATA_WRITE    4
+#define CPC_PTL_PACKET_TYPE_WRITE_DATA         5
+#define CPC_PTL_PACKET_TYPE_COND_WRITE         6
+#define CPC_PTL_PACKET_TYPE_WAIT_REG_MEM       7
+#define CPC_PTL_PACKET_TYPE_WAIT_REG_MEM64     8
+
+/* CPC_INT_CNTX_ID[31:28]: packet type that was skipped */
+#define CPC_INT_CNTX_ID__PACKET_TYPE__SHIFT    28
+#define CPC_INT_CNTX_ID__PACKET_TYPE_MASK      0xF0000000
+
+/* CPC_INT_INFO[30:28]: queue ID */
+#define CPC_INT_INFO__QUEUE_ID__SHIFT          28
+#define CPC_INT_INFO__QUEUE_ID_MASK            0x70000000
+
 /*
  * The debugger will send user data(m0) with PRIV=1 to indicate it requires
  * notification from the KFD with the following queue id (DOORBELL_ID) and
@@ -142,6 +164,30 @@ enum SQ_INTERRUPT_ERROR_TYPE {
                                KFD_DEBUG_CP_BAD_OP_ECODE_MASK)         \
                                >> KFD_DEBUG_CP_BAD_OP_ECODE_SHIFT)
 
+static const char *cpc_packet_type_name(uint32_t packet_type)
+{
+       switch (packet_type) {
+       case CPC_PTL_PACKET_TYPE_SET_UCONFIG_REG:
+               return "SET_UCONFIG_REG";
+       case CPC_PTL_PACKET_TYPE_SET_SH_REG:
+               return "SET_SH_REG";
+       case CPC_PTL_PACKET_TYPE_COPY_DATA_READ:
+               return "COPY_DATA_READ";
+       case CPC_PTL_PACKET_TYPE_COPY_DATA_WRITE:
+               return "COPY_DATA_WRITE";
+       case CPC_PTL_PACKET_TYPE_WRITE_DATA:
+               return "WRITE_DATA";
+       case CPC_PTL_PACKET_TYPE_COND_WRITE:
+               return "COND_WRITE";
+       case CPC_PTL_PACKET_TYPE_WAIT_REG_MEM:
+               return "WAIT_REG_MEM";
+       case CPC_PTL_PACKET_TYPE_WAIT_REG_MEM64:
+               return "WAIT_REG_MEM64";
+       default:
+               return "UNKNOWN";
+       }
+}
+
 static void event_interrupt_poison_consumption_v9(struct kfd_node *dev,
                                uint16_t pasid, uint16_t client_id)
 {
@@ -352,6 +398,8 @@ static bool event_interrupt_isr_v9(struct kfd_node *dev,
                source_id == SOC15_INTSRC_SDMA_ECC ||
                source_id == SOC15_INTSRC_SQ_INTERRUPT_MSG ||
                source_id == SOC15_INTSRC_CP_BAD_OPCODE ||
+               (client_id == SOC15_IH_CLIENTID_GRBM_CP &&
+                source_id == SOC15_INTSRC_CP_PTL_REG_SKIP) ||
                KFD_IRQ_IS_FENCE(client_id, source_id) ||
                ((client_id == SOC15_IH_CLIENTID_VMC ||
                client_id == SOC15_IH_CLIENTID_VMC1 ||
@@ -538,6 +586,34 @@ static void event_interrupt_wq_v9(struct kfd_node *dev,
                                KFD_DEBUG_DOORBELL_ID(context_id0),
                                
KFD_EC_MASK(KFD_DEBUG_CP_BAD_OP_ECODE(context_id0)),
                                NULL, 0);
+               } else if (source_id == SOC15_INTSRC_CP_PTL_REG_SKIP) {
+                       uint32_t packet_type, queue_id;
+                       uint32_t skipped_addr;
+
+                       /*
+                        * PTL (Peak TOPS Limiter) register skip notification.
+                        * FW skipped a privileged register access and is 
notifying KFD.
+                        * Data from IH entry (not registers):
+                        * - context_id0 contains CPC_INT_CNTX_ID with packet 
type in [31:28]
+                        * - context_id1 contains CPC_INT_INFO with queue ID in 
[30:28]
+                        * - context_id2 contains CPC_INT_ADDR (skipped 
register address)
+                        * - PASID comes from CPC_INT_PASID (already extracted 
from IH entry)
+                        */
+                       skipped_addr = 
SOC15_CONTEXT_ID2_FROM_IH_ENTRY(ih_ring_entry);
+
+                       /* Extract packet type from CPC_INT_CNTX_ID[31:28] */
+                       packet_type = (context_id0 & 
CPC_INT_CNTX_ID__PACKET_TYPE_MASK) >>
+                                       CPC_INT_CNTX_ID__PACKET_TYPE__SHIFT;
+
+                       /* Extract queue ID from CPC_INT_INFO[30:28] */
+                       queue_id = (context_id1 & CPC_INT_INFO__QUEUE_ID_MASK) 
>>
+                                       CPC_INT_INFO__QUEUE_ID__SHIFT;
+
+                       dev_info_ratelimited(dev->adev->dev,
+                               "PTL: AQL request was rejected due to 
incompatible user input; please verify your PTL configuration.");
+                       dev_dbg_ratelimited(dev->adev->dev,
+                               "PTL: register access skipped - pasid 0x%x, 
queue %u, packet %s, addr 0x%x\n",
+                               pasid, queue_id, 
cpc_packet_type_name(packet_type), skipped_addr);
                }
        } else if (client_id == SOC15_IH_CLIENTID_SDMA0 ||
                   client_id == SOC15_IH_CLIENTID_SDMA1 ||
diff --git a/drivers/gpu/drm/amd/amdkfd/soc15_int.h 
b/drivers/gpu/drm/amd/amdkfd/soc15_int.h
index e5c0205f2618..736b02ccdefb 100644
--- a/drivers/gpu/drm/amd/amdkfd/soc15_int.h
+++ b/drivers/gpu/drm/amd/amdkfd/soc15_int.h
@@ -25,6 +25,7 @@
 
 #include "soc15_ih_clientid.h"
 
+#define SOC15_INTSRC_CP_PTL_REG_SKIP   177
 #define SOC15_INTSRC_CP_END_OF_PIPE    181
 #define SOC15_INTSRC_CP_BAD_OPCODE     183
 #define SOC15_INTSRC_SQ_INTERRUPT_MSG  239
-- 
2.43.0

Reply via email to