drm/amdgpu: enable IH ring 1 and ring 2 for navi
authorAlex Sierra <alex.sierra@amd.com>
Mon, 23 Mar 2020 18:28:15 +0000 (13:28 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 1 Apr 2020 18:44:44 +0000 (14:44 -0400)
Support added into IH to enable ring1 and ring2 for navi10_ih.

Signed-off-by: Alex Sierra <alex.sierra@amd.com>
Reviewed-by: Felix Kuehling <Felix.Kuehling@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/amdgpu/navi10_ih.c

index e08245a..0c0ba57 100644 (file)
@@ -51,6 +51,22 @@ static void navi10_ih_enable_interrupts(struct amdgpu_device *adev)
        ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, ENABLE_INTR, 1);
        WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL, ih_rb_cntl);
        adev->irq.ih.enabled = true;
+
+       if (adev->irq.ih1.ring_size) {
+               ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
+               ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1,
+                                          RB_ENABLE, 1);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
+               adev->irq.ih1.enabled = true;
+       }
+
+       if (adev->irq.ih2.ring_size) {
+               ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
+               ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2,
+                                          RB_ENABLE, 1);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
+               adev->irq.ih2.enabled = true;
+       }
 }
 
 /**
@@ -72,6 +88,31 @@ static void navi10_ih_disable_interrupts(struct amdgpu_device *adev)
        WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR, 0);
        adev->irq.ih.enabled = false;
        adev->irq.ih.rptr = 0;
+
+       if (adev->irq.ih1.ring_size) {
+               ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
+               ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING1,
+                                          RB_ENABLE, 0);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
+               /* set rptr, wptr to 0 */
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0);
+               adev->irq.ih1.enabled = false;
+               adev->irq.ih1.rptr = 0;
+       }
+
+       if (adev->irq.ih2.ring_size) {
+               ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
+               ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL_RING2,
+                                          RB_ENABLE, 0);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
+               /* set rptr, wptr to 0 */
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0);
+               adev->irq.ih2.enabled = false;
+               adev->irq.ih2.rptr = 0;
+       }
+
 }
 
 static uint32_t navi10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl)
@@ -97,6 +138,25 @@ static uint32_t navi10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl
        return ih_rb_cntl;
 }
 
+static uint32_t navi10_ih_doorbell_rptr(struct amdgpu_ih_ring *ih)
+{
+       u32 ih_doorbell_rtpr = 0;
+
+       if (ih->use_doorbell) {
+               ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
+                                                IH_DOORBELL_RPTR, OFFSET,
+                                                ih->doorbell_index);
+               ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
+                                                IH_DOORBELL_RPTR,
+                                                ENABLE, 1);
+       } else {
+               ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
+                                                IH_DOORBELL_RPTR,
+                                                ENABLE, 0);
+       }
+       return ih_doorbell_rtpr;
+}
+
 /**
  * navi10_ih_irq_init - init and enable the interrupt ring
  *
@@ -111,7 +171,7 @@ static uint32_t navi10_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl
 static int navi10_ih_irq_init(struct amdgpu_device *adev)
 {
        struct amdgpu_ih_ring *ih = &adev->irq.ih;
-       u32 ih_rb_cntl, ih_doorbell_rtpr, ih_chicken;
+       u32 ih_rb_cntl, ih_chicken;
        u32 tmp;
 
        /* disable irqs */
@@ -149,22 +209,52 @@ static int navi10_ih_irq_init(struct amdgpu_device *adev)
        WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, 0);
        WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR, 0);
 
-       ih_doorbell_rtpr = RREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR);
-       if (ih->use_doorbell) {
-               ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
-                                                IH_DOORBELL_RPTR, OFFSET,
-                                                ih->doorbell_index);
-               ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
-                                                IH_DOORBELL_RPTR, ENABLE, 1);
-       } else {
-               ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
-                                                IH_DOORBELL_RPTR, ENABLE, 0);
-       }
-       WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR, ih_doorbell_rtpr);
+       WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR,
+                       navi10_ih_doorbell_rptr(ih));
 
        adev->nbio.funcs->ih_doorbell_range(adev, ih->use_doorbell,
                                            ih->doorbell_index);
 
+       ih = &adev->irq.ih1;
+       if (ih->ring_size) {
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING1, ih->gpu_addr >> 8);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING1,
+                            (ih->gpu_addr >> 40) & 0xff);
+
+               ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1);
+               ih_rb_cntl = navi10_ih_rb_cntl(ih, ih_rb_cntl);
+               ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
+                                          WPTR_OVERFLOW_ENABLE, 0);
+               ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
+                                          RB_FULL_DRAIN_ENABLE, 1);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING1, ih_rb_cntl);
+               /* set rptr, wptr to 0 */
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING1, 0);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, 0);
+
+               WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1,
+                               navi10_ih_doorbell_rptr(ih));
+       }
+
+       ih = &adev->irq.ih2;
+       if (ih->ring_size) {
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_RING2, ih->gpu_addr >> 8);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_BASE_HI_RING2,
+                            (ih->gpu_addr >> 40) & 0xff);
+
+               ih_rb_cntl = RREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2);
+               ih_rb_cntl = navi10_ih_rb_cntl(ih, ih_rb_cntl);
+
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_CNTL_RING2, ih_rb_cntl);
+               /* set rptr, wptr to 0 */
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_WPTR_RING2, 0);
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, 0);
+
+               WREG32_SOC15(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2,
+                            navi10_ih_doorbell_rptr(ih));
+       }
+
+
        tmp = RREG32_SOC15(OSSSYS, 0, mmIH_STORM_CLIENT_LIST_CNTL);
        tmp = REG_SET_FIELD(tmp, IH_STORM_CLIENT_LIST_CNTL,
                            CLIENT18_IS_STORM_CLIENT, 1);
@@ -217,7 +307,15 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev,
        if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
                goto out;
 
-       reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
+       if (ih == &adev->irq.ih)
+               reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
+       else if (ih == &adev->irq.ih1)
+               reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
+       else if (ih == &adev->irq.ih2)
+               reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
+       else
+               BUG();
+
        wptr = RREG32_NO_KIQ(reg);
        if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
                goto out;
@@ -233,7 +331,15 @@ static u32 navi10_ih_get_wptr(struct amdgpu_device *adev,
                 wptr, ih->rptr, tmp);
        ih->rptr = tmp;
 
-       reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
+       if (ih == &adev->irq.ih)
+               reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
+       else if (ih == &adev->irq.ih1)
+               reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
+       else if (ih == &adev->irq.ih2)
+               reg = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
+       else
+               BUG();
+
        tmp = RREG32_NO_KIQ(reg);
        tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
        WREG32_NO_KIQ(reg, tmp);
@@ -333,8 +439,52 @@ static void navi10_ih_set_rptr(struct amdgpu_device *adev,
 
                if (amdgpu_sriov_vf(adev))
                        navi10_ih_irq_rearm(adev, ih);
-       } else
+       } else if (ih == &adev->irq.ih) {
                WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR, ih->rptr);
+       } else if (ih == &adev->irq.ih1) {
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING1, ih->rptr);
+       } else if (ih == &adev->irq.ih2) {
+               WREG32_SOC15(OSSSYS, 0, mmIH_RB_RPTR_RING2, ih->rptr);
+       }
+}
+
+/**
+ * navi10_ih_self_irq - dispatch work for ring 1 and 2
+ *
+ * @adev: amdgpu_device pointer
+ * @source: irq source
+ * @entry: IV with WPTR update
+ *
+ * Update the WPTR from the IV and schedule work to handle the entries.
+ */
+static int navi10_ih_self_irq(struct amdgpu_device *adev,
+                             struct amdgpu_irq_src *source,
+                             struct amdgpu_iv_entry *entry)
+{
+       uint32_t wptr = cpu_to_le32(entry->src_data[0]);
+
+       switch (entry->ring_id) {
+       case 1:
+               *adev->irq.ih1.wptr_cpu = wptr;
+               schedule_work(&adev->irq.ih1_work);
+               break;
+       case 2:
+               *adev->irq.ih2.wptr_cpu = wptr;
+               schedule_work(&adev->irq.ih2_work);
+               break;
+       default: break;
+       }
+       return 0;
+}
+
+static const struct amdgpu_irq_src_funcs navi10_ih_self_irq_funcs = {
+       .process = navi10_ih_self_irq,
+};
+
+static void navi10_ih_set_self_irq_funcs(struct amdgpu_device *adev)
+{
+       adev->irq.self_irq.num_types = 0;
+       adev->irq.self_irq.funcs = &navi10_ih_self_irq_funcs;
 }
 
 static int navi10_ih_early_init(void *handle)
@@ -342,6 +492,7 @@ static int navi10_ih_early_init(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        navi10_ih_set_interrupt_funcs(adev);
+       navi10_ih_set_self_irq_funcs(adev);
        return 0;
 }
 
@@ -351,6 +502,12 @@ static int navi10_ih_sw_init(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
        bool use_bus_addr;
 
+       r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0,
+                               &adev->irq.self_irq);
+
+       if (r)
+               return r;
+
        /* use gpu virtual address for ih ring
         * until ih_checken is programmed to allow
         * use bus address for ih ring by psp bl */
@@ -363,6 +520,20 @@ static int navi10_ih_sw_init(void *handle)
        adev->irq.ih.use_doorbell = true;
        adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1;
 
+       r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true);
+       if (r)
+               return r;
+
+       adev->irq.ih1.use_doorbell = true;
+       adev->irq.ih1.doorbell_index = (adev->doorbell_index.ih + 1) << 1;
+
+       r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true);
+       if (r)
+               return r;
+
+       adev->irq.ih2.use_doorbell = true;
+       adev->irq.ih2.doorbell_index = (adev->doorbell_index.ih + 2) << 1;
+
        r = amdgpu_irq_init(adev);
 
        return r;
@@ -373,6 +544,8 @@ static int navi10_ih_sw_fini(void *handle)
        struct amdgpu_device *adev = (struct amdgpu_device *)handle;
 
        amdgpu_irq_fini(adev);
+       amdgpu_ih_ring_fini(adev, &adev->irq.ih2);
+       amdgpu_ih_ring_fini(adev, &adev->irq.ih1);
        amdgpu_ih_ring_fini(adev, &adev->irq.ih);
 
        return 0;