From: Philip Yang <[email protected]>

Register the UALink IRQ source with the IH subsystem. Hardware IH
entries are re-queued onto a dedicated soft ring and drained by a work
queue handler. Add the soft ring, worker, and delegate helper to the
IRQ layer.

Signed-off-by: Philip Yang <[email protected]>
Reviewed-by: Felix Kuehling <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
---
 drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c    | 17 +++++
 drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h    |  7 +-
 drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c | 82 ++++++++++++++++++++++
 drivers/gpu/drm/amd/amdgpu/ih_v7_0.c       |  8 +++
 4 files changed, 112 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
index 91f1ca95ea543..dcf90a974326d 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.c
@@ -264,6 +264,14 @@ static void amdgpu_irq_handle_ih_psp(struct work_struct 
*work)
 
        amdgpu_ih_process(adev, &adev->irq.ih_psp);
 }
+       
+static void amdgpu_irq_handle_ih_ualink(struct work_struct *work)
+{
+       struct amdgpu_device *adev = container_of(work, struct amdgpu_device,
+                                                 irq.ih_ualink_work);
+
+       amdgpu_ih_process(adev, &adev->irq.ih_ualink);
+}
 
 /**
  * amdgpu_msi_ok - check whether MSI functionality is enabled
@@ -341,6 +349,7 @@ int amdgpu_irq_init(struct amdgpu_device *adev)
        INIT_WORK(&adev->irq.ih2_work, amdgpu_irq_handle_ih2);
        INIT_WORK(&adev->irq.ih_soft_work, amdgpu_irq_handle_ih_soft);
        INIT_WORK(&adev->irq.ih_psp_work, amdgpu_irq_handle_ih_psp);
+       INIT_WORK(&adev->irq.ih_ualink_work, amdgpu_irq_handle_ih_ualink);
 
        /* Use vector 0 for MSI-X. */
        r = pci_irq_vector(adev->pdev, 0);
@@ -566,6 +575,14 @@ void amdgpu_irq_psp_delegate(struct amdgpu_device *adev,
        schedule_work(&adev->irq.ih_psp_work);
 }
 
+void amdgpu_irq_ualink_delegate(struct amdgpu_device *adev,
+                               struct amdgpu_iv_entry *entry,
+                               unsigned int num_dw)
+{
+       amdgpu_ih_ring_write(adev, &adev->irq.ih_ualink, entry->iv_entry, 
num_dw);
+       schedule_work(&adev->irq.ih_ualink_work);
+}
+
 /**
  * amdgpu_irq_update - update hardware interrupt state
  *
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
index deee64b69885d..c88431471c303 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_irq.h
@@ -90,10 +90,10 @@ struct amdgpu_irq {
        bool                            msi_enabled; /* msi enabled */
 
        /* interrupt rings */
-       struct amdgpu_ih_ring           ih, ih1, ih2, ih_soft, ih_psp;
+       struct amdgpu_ih_ring           ih, ih1, ih2, ih_soft, ih_psp, 
ih_ualink;
        const struct amdgpu_ih_funcs    *ih_funcs;
        struct work_struct              ih1_work, ih2_work, ih_soft_work,
-                                       ih_psp_work;
+                                       ih_psp_work, ih_ualink_work;
        struct amdgpu_irq_src           self_irq;
 
        /* gen irq stuff */
@@ -138,6 +138,9 @@ void amdgpu_irq_delegate(struct amdgpu_device *adev,
 void amdgpu_irq_psp_delegate(struct amdgpu_device *adev,
                             struct amdgpu_iv_entry *entry,
                             unsigned int num_dw);
+void amdgpu_irq_ualink_delegate(struct amdgpu_device *adev,
+                                struct amdgpu_iv_entry *entry,
+                                unsigned int num_dw);
 int amdgpu_irq_update(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
                      unsigned type);
 int amdgpu_irq_get(struct amdgpu_device *adev, struct amdgpu_irq_src *src,
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c 
b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
index d1e8f51a88b2d..2d2b1b1145cd4 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_ualink.c
@@ -62,6 +62,13 @@ int amdgpu_ualink_init(struct amdgpu_device *adev)
                return r;
        }
 
+       r = amdgpu_ualink_init_interrupt(adev);
+       if (r) {
+               dev_err(adev->dev,
+                       "Failed to enable UALink irq: %d\n", r);
+               return r;
+       }
+
        return 0;
 }
 
@@ -3109,3 +3116,78 @@ void amdgpu_ualink_sw_fini(struct amdgpu_device *adev)
        adev->ualink.remote = NULL;
 }
 
+static int amdgpu_ualink_process_irq(struct amdgpu_device *adev,
+                                    struct amdgpu_irq_src *source,
+                                    struct amdgpu_iv_entry *entry)
+{
+       int handled = 1;
+
+       dev_dbg(adev->dev, "%s client_id 0x%x src_id 0x%x ih\n",
+               entry->ih == &adev->irq.ih ? "ring" : "ualink soft ring",
+               entry->client_id, entry->src_id);
+
+       /* Copy IH entry into ualink soft ring. */
+       if (entry->ih == &adev->irq.ih) {
+               dev_dbg(adev->dev, "delegate to ualink irq soft ring\n");
+               amdgpu_irq_ualink_delegate(adev, entry, 8);
+               return handled;
+       }
+
+       /*
+        * Call amdgpu_ualink_interrupt handler
+        * amdgpu_ualink_interrupt(adev, entry);
+        */
+
+       return handled;
+}
+
+static int amdgpu_ualink_set_irq_state(struct amdgpu_device *adev,
+                                       struct amdgpu_irq_src *source,
+                                       u32 type,
+                                       enum amdgpu_interrupt_state state)
+{
+       /*
+        * Don't set register to enable/disable nHT controller interrupt.
+        *
+        * F/W running on MP2, which can always send cookie to IH block to
+        * interrupt driver.
+        */
+       dev_dbg(adev->dev, "ualink interrupt %s\n",
+               state == AMDGPU_IRQ_STATE_ENABLE ? "enable" : "disable");
+       return 0;
+}
+
+static const struct amdgpu_irq_src_funcs ualink_irq_funcs = {
+       .set = amdgpu_ualink_set_irq_state,
+       .process = amdgpu_ualink_process_irq,
+};
+
+/* TODO: if move to header file soc21_enum.h */
+#define UALINK_IH_CLIENT_ID 0x1C
+#define UALINK_IH_SOURCE_ID 0x0
+
+/**
+ * amdgpu_ualink_init_interrupt - initialization of UALink IRQ
+ * @adev: amdgpu device pointer
+ *
+ * Registers the UALink interrupt source with the IH (Interrupt Handler)
+ * subsystem during early device initialization. This sets up the IRQ
+ * callback functions for handling remote interrupts from peer GPUs.
+ *
+ * Return: 0 on success, negative error code on failure
+ */
+int amdgpu_ualink_init_interrupt(struct amdgpu_device *adev)
+{
+       int r;
+
+       dev_dbg(adev->dev, "init ualink irq client_id 0x%x src_id 0x%x\n",
+               UALINK_IH_CLIENT_ID, UALINK_IH_SOURCE_ID);
+
+       adev->ualink.irq.num_types = 1;
+       adev->ualink.irq.funcs = &ualink_irq_funcs;
+
+       r = amdgpu_irq_add_id(adev, UALINK_IH_CLIENT_ID,
+                             UALINK_IH_SOURCE_ID, &adev->ualink.irq);
+       return r;
+}
+
diff --git a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c 
b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c
index 58d5156a44dbc..c93ef937c4309 100644
--- a/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c
+++ b/drivers/gpu/drm/amd/amdgpu/ih_v7_0.c
@@ -424,6 +424,9 @@ static int ih_v7_0_irq_init(struct amdgpu_device *adev)
        if (adev->irq.ih_psp.ring_size)
                adev->irq.ih_psp.enabled = true;
 
+       if (adev->irq.ih_ualink.ring_size)
+               adev->irq.ih_ualink.enabled = true;
+
        return 0;
 }
 
@@ -639,6 +642,11 @@ static int ih_v7_0_sw_init(struct amdgpu_ip_block 
*ip_block)
        if (r)
                return r;
 
+       dev_dbg(adev->dev, "ualink init ih_ualink\n");
+       r = amdgpu_ih_ring_init(adev, &adev->irq.ih_ualink, sw_ring_size, true);
+       if (r)
+               return r;
+
        r = amdgpu_irq_init(adev);
 
        return r;
-- 
2.55.0

Reply via email to