Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright 2020 Advanced Micro Devices, Inc.
0003  *
0004  * Permission is hereby granted, free of charge, to any person obtaining a
0005  * copy of this software and associated documentation files (the "Software"),
0006  * to deal in the Software without restriction, including without limitation
0007  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
0008  * and/or sell copies of the Software, and to permit persons to whom the
0009  * Software is furnished to do so, subject to the following conditions:
0010  *
0011  * The above copyright notice and this permission notice shall be included in
0012  * all copies or substantial portions of the Software.
0013  *
0014  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0015  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0016  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
0017  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
0018  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
0019  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
0020  * OTHER DEALINGS IN THE SOFTWARE.
0021  *
0022  */
0023 
0024 #include <linux/pci.h>
0025 
0026 #include "amdgpu.h"
0027 #include "amdgpu_ih.h"
0028 #include "soc15.h"
0029 
0030 #include "oss/osssys_4_2_0_offset.h"
0031 #include "oss/osssys_4_2_0_sh_mask.h"
0032 
0033 #include "soc15_common.h"
0034 #include "vega20_ih.h"
0035 
0036 #define MAX_REARM_RETRY 10
0037 
0038 #define mmIH_CHICKEN_ALDEBARAN          0x18d
0039 #define mmIH_CHICKEN_ALDEBARAN_BASE_IDX     0
0040 
0041 static void vega20_ih_set_interrupt_funcs(struct amdgpu_device *adev);
0042 
0043 /**
0044  * vega20_ih_init_register_offset - Initialize register offset for ih rings
0045  *
0046  * @adev: amdgpu_device pointer
0047  *
0048  * Initialize register offset ih rings (VEGA20).
0049  */
0050 static void vega20_ih_init_register_offset(struct amdgpu_device *adev)
0051 {
0052     struct amdgpu_ih_regs *ih_regs;
0053 
0054     if (adev->irq.ih.ring_size) {
0055         ih_regs = &adev->irq.ih.ih_regs;
0056         ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE);
0057         ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI);
0058         ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL);
0059         ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR);
0060         ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR);
0061         ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR);
0062         ih_regs->ih_rb_wptr_addr_lo = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_LO);
0063         ih_regs->ih_rb_wptr_addr_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_ADDR_HI);
0064         ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL;
0065     }
0066 
0067     if (adev->irq.ih1.ring_size) {
0068         ih_regs = &adev->irq.ih1.ih_regs;
0069         ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING1);
0070         ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING1);
0071         ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING1);
0072         ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING1);
0073         ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING1);
0074         ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING1);
0075         ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING1;
0076     }
0077 
0078     if (adev->irq.ih2.ring_size) {
0079         ih_regs = &adev->irq.ih2.ih_regs;
0080         ih_regs->ih_rb_base = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_RING2);
0081         ih_regs->ih_rb_base_hi = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_BASE_HI_RING2);
0082         ih_regs->ih_rb_cntl = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_CNTL_RING2);
0083         ih_regs->ih_rb_wptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_WPTR_RING2);
0084         ih_regs->ih_rb_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_RB_RPTR_RING2);
0085         ih_regs->ih_doorbell_rptr = SOC15_REG_OFFSET(OSSSYS, 0, mmIH_DOORBELL_RPTR_RING2);
0086         ih_regs->psp_reg_id = PSP_REG_IH_RB_CNTL_RING2;
0087     }
0088 }
0089 
0090 /**
0091  * vega20_ih_toggle_ring_interrupts - toggle the interrupt ring buffer
0092  *
0093  * @adev: amdgpu_device pointer
0094  * @ih: amdgpu_ih_ring pointer
0095  * @enable: true - enable the interrupts, false - disable the interrupts
0096  *
0097  * Toggle the interrupt ring buffer (VEGA20)
0098  */
0099 static int vega20_ih_toggle_ring_interrupts(struct amdgpu_device *adev,
0100                         struct amdgpu_ih_ring *ih,
0101                         bool enable)
0102 {
0103     struct amdgpu_ih_regs *ih_regs;
0104     uint32_t tmp;
0105 
0106     ih_regs = &ih->ih_regs;
0107 
0108     tmp = RREG32(ih_regs->ih_rb_cntl);
0109     tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_ENABLE, (enable ? 1 : 0));
0110     tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_GPU_TS_ENABLE, 1);
0111 
0112     /* enable_intr field is only valid in ring0 */
0113     if (ih == &adev->irq.ih)
0114         tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, ENABLE_INTR, (enable ? 1 : 0));
0115     if (amdgpu_sriov_vf(adev)) {
0116         if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) {
0117             dev_err(adev->dev, "PSP program IH_RB_CNTL failed!\n");
0118             return -ETIMEDOUT;
0119         }
0120     } else {
0121         WREG32(ih_regs->ih_rb_cntl, tmp);
0122     }
0123 
0124     if (enable) {
0125         ih->enabled = true;
0126     } else {
0127         /* set rptr, wptr to 0 */
0128         WREG32(ih_regs->ih_rb_rptr, 0);
0129         WREG32(ih_regs->ih_rb_wptr, 0);
0130         ih->enabled = false;
0131         ih->rptr = 0;
0132     }
0133 
0134     return 0;
0135 }
0136 
0137 /**
0138  * vega20_ih_toggle_interrupts - Toggle all the available interrupt ring buffers
0139  *
0140  * @adev: amdgpu_device pointer
0141  * @enable: enable or disable interrupt ring buffers
0142  *
0143  * Toggle all the available interrupt ring buffers (VEGA20).
0144  */
0145 static int vega20_ih_toggle_interrupts(struct amdgpu_device *adev, bool enable)
0146 {
0147     struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
0148     int i;
0149     int r;
0150 
0151     for (i = 0; i < ARRAY_SIZE(ih); i++) {
0152         if (ih[i]->ring_size) {
0153             r = vega20_ih_toggle_ring_interrupts(adev, ih[i], enable);
0154             if (r)
0155                 return r;
0156         }
0157     }
0158 
0159     return 0;
0160 }
0161 
0162 static uint32_t vega20_ih_rb_cntl(struct amdgpu_ih_ring *ih, uint32_t ih_rb_cntl)
0163 {
0164     int rb_bufsz = order_base_2(ih->ring_size / 4);
0165 
0166     ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
0167                    MC_SPACE, ih->use_bus_addr ? 1 : 4);
0168     ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
0169                    WPTR_OVERFLOW_CLEAR, 1);
0170     ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
0171                    WPTR_OVERFLOW_ENABLE, 1);
0172     ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, RB_SIZE, rb_bufsz);
0173     /* Ring Buffer write pointer writeback. If enabled, IH_RB_WPTR register
0174      * value is written to memory
0175      */
0176     ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL,
0177                    WPTR_WRITEBACK_ENABLE, 1);
0178     ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_SNOOP, 1);
0179     ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_RO, 0);
0180     ih_rb_cntl = REG_SET_FIELD(ih_rb_cntl, IH_RB_CNTL, MC_VMID, 0);
0181 
0182     return ih_rb_cntl;
0183 }
0184 
0185 static uint32_t vega20_ih_doorbell_rptr(struct amdgpu_ih_ring *ih)
0186 {
0187     u32 ih_doorbell_rtpr = 0;
0188 
0189     if (ih->use_doorbell) {
0190         ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
0191                          IH_DOORBELL_RPTR, OFFSET,
0192                          ih->doorbell_index);
0193         ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
0194                          IH_DOORBELL_RPTR,
0195                          ENABLE, 1);
0196     } else {
0197         ih_doorbell_rtpr = REG_SET_FIELD(ih_doorbell_rtpr,
0198                          IH_DOORBELL_RPTR,
0199                          ENABLE, 0);
0200     }
0201     return ih_doorbell_rtpr;
0202 }
0203 
0204 /**
0205  * vega20_ih_enable_ring - enable an ih ring buffer
0206  *
0207  * @adev: amdgpu_device pointer
0208  * @ih: amdgpu_ih_ring pointer
0209  *
0210  * Enable an ih ring buffer (VEGA20)
0211  */
0212 static int vega20_ih_enable_ring(struct amdgpu_device *adev,
0213                  struct amdgpu_ih_ring *ih)
0214 {
0215     struct amdgpu_ih_regs *ih_regs;
0216     uint32_t tmp;
0217 
0218     ih_regs = &ih->ih_regs;
0219 
0220     /* Ring Buffer base. [39:8] of 40-bit address of the beginning of the ring buffer*/
0221     WREG32(ih_regs->ih_rb_base, ih->gpu_addr >> 8);
0222     WREG32(ih_regs->ih_rb_base_hi, (ih->gpu_addr >> 40) & 0xff);
0223 
0224     tmp = RREG32(ih_regs->ih_rb_cntl);
0225     tmp = vega20_ih_rb_cntl(ih, tmp);
0226     if (ih == &adev->irq.ih)
0227         tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RPTR_REARM, !!adev->irq.msi_enabled);
0228     if (ih == &adev->irq.ih1)
0229         tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, RB_FULL_DRAIN_ENABLE, 1);
0230     if (amdgpu_sriov_vf(adev)) {
0231         if (psp_reg_program(&adev->psp, ih_regs->psp_reg_id, tmp)) {
0232             dev_err(adev->dev, "PSP program IH_RB_CNTL failed!\n");
0233             return -ETIMEDOUT;
0234         }
0235     } else {
0236         WREG32(ih_regs->ih_rb_cntl, tmp);
0237     }
0238 
0239     if (ih == &adev->irq.ih) {
0240         /* set the ih ring 0 writeback address whether it's enabled or not */
0241         WREG32(ih_regs->ih_rb_wptr_addr_lo, lower_32_bits(ih->wptr_addr));
0242         WREG32(ih_regs->ih_rb_wptr_addr_hi, upper_32_bits(ih->wptr_addr) & 0xFFFF);
0243     }
0244 
0245     /* set rptr, wptr to 0 */
0246     WREG32(ih_regs->ih_rb_wptr, 0);
0247     WREG32(ih_regs->ih_rb_rptr, 0);
0248 
0249     WREG32(ih_regs->ih_doorbell_rptr, vega20_ih_doorbell_rptr(ih));
0250 
0251     return 0;
0252 }
0253 
0254 /**
0255  * vega20_ih_reroute_ih - reroute VMC/UTCL2 ih to an ih ring
0256  *
0257  * @adev: amdgpu_device pointer
0258  *
0259  * Reroute VMC and UMC interrupts on primary ih ring to
0260  * ih ring 1 so they won't lose when bunches of page faults
0261  * interrupts overwhelms the interrupt handler(VEGA20)
0262  */
0263 static void vega20_ih_reroute_ih(struct amdgpu_device *adev)
0264 {
0265     uint32_t tmp;
0266 
0267     /* vega20 ih reroute will go through psp this
0268      * function is used for newer asics starting arcturus
0269      */
0270     if (adev->asic_type >= CHIP_ARCTURUS) {
0271         /* Reroute to IH ring 1 for VMC */
0272         WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x12);
0273         tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA);
0274         tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, CLIENT_TYPE, 1);
0275         tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
0276         WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp);
0277 
0278         /* Reroute IH ring 1 for UTCL2 */
0279         WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_INDEX, 0x1B);
0280         tmp = RREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA);
0281         tmp = REG_SET_FIELD(tmp, IH_CLIENT_CFG_DATA, RING_ID, 1);
0282         WREG32_SOC15(OSSSYS, 0, mmIH_CLIENT_CFG_DATA, tmp);
0283     }
0284 }
0285 
0286 /**
0287  * vega20_ih_irq_init - init and enable the interrupt ring
0288  *
0289  * @adev: amdgpu_device pointer
0290  *
0291  * Allocate a ring buffer for the interrupt controller,
0292  * enable the RLC, disable interrupts, enable the IH
0293  * ring buffer and enable it (VI).
0294  * Called at device load and reume.
0295  * Returns 0 for success, errors for failure.
0296  */
0297 static int vega20_ih_irq_init(struct amdgpu_device *adev)
0298 {
0299     struct amdgpu_ih_ring *ih[] = {&adev->irq.ih, &adev->irq.ih1, &adev->irq.ih2};
0300     u32 ih_chicken;
0301     int ret;
0302     int i;
0303 
0304     /* disable irqs */
0305     ret = vega20_ih_toggle_interrupts(adev, false);
0306     if (ret)
0307         return ret;
0308 
0309     adev->nbio.funcs->ih_control(adev);
0310 
0311     if (adev->asic_type == CHIP_ARCTURUS &&
0312         adev->firmware.load_type == AMDGPU_FW_LOAD_DIRECT) {
0313         ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN);
0314         if (adev->irq.ih.use_bus_addr) {
0315             ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN,
0316                            MC_SPACE_GPA_ENABLE, 1);
0317         }
0318         WREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN, ih_chicken);
0319     }
0320 
0321     /* psp firmware won't program IH_CHICKEN for aldebaran
0322      * driver needs to program it properly according to
0323      * MC_SPACE type in IH_RB_CNTL */
0324     if (adev->asic_type == CHIP_ALDEBARAN) {
0325         ih_chicken = RREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN_ALDEBARAN);
0326         if (adev->irq.ih.use_bus_addr) {
0327             ih_chicken = REG_SET_FIELD(ih_chicken, IH_CHICKEN,
0328                            MC_SPACE_GPA_ENABLE, 1);
0329         }
0330         WREG32_SOC15(OSSSYS, 0, mmIH_CHICKEN_ALDEBARAN, ih_chicken);
0331     }
0332 
0333     for (i = 0; i < ARRAY_SIZE(ih); i++) {
0334         if (ih[i]->ring_size) {
0335             if (i == 1)
0336                 vega20_ih_reroute_ih(adev);
0337             ret = vega20_ih_enable_ring(adev, ih[i]);
0338             if (ret)
0339                 return ret;
0340         }
0341     }
0342 
0343     if (!amdgpu_sriov_vf(adev))
0344         adev->nbio.funcs->ih_doorbell_range(adev, adev->irq.ih.use_doorbell,
0345                             adev->irq.ih.doorbell_index);
0346 
0347     pci_set_master(adev->pdev);
0348 
0349     /* enable interrupts */
0350     ret = vega20_ih_toggle_interrupts(adev, true);
0351     if (ret)
0352         return ret;
0353 
0354     if (adev->irq.ih_soft.ring_size)
0355         adev->irq.ih_soft.enabled = true;
0356 
0357     return 0;
0358 }
0359 
0360 /**
0361  * vega20_ih_irq_disable - disable interrupts
0362  *
0363  * @adev: amdgpu_device pointer
0364  *
0365  * Disable interrupts on the hw (VEGA20).
0366  */
0367 static void vega20_ih_irq_disable(struct amdgpu_device *adev)
0368 {
0369     vega20_ih_toggle_interrupts(adev, false);
0370 
0371     /* Wait and acknowledge irq */
0372     mdelay(1);
0373 }
0374 
0375 /**
0376  * vega20_ih_get_wptr - get the IH ring buffer wptr
0377  *
0378  * @adev: amdgpu_device pointer
0379  * @ih: amdgpu_ih_ring pointer
0380  *
0381  * Get the IH ring buffer wptr from either the register
0382  * or the writeback memory buffer (VEGA20).  Also check for
0383  * ring buffer overflow and deal with it.
0384  * Returns the value of the wptr.
0385  */
0386 static u32 vega20_ih_get_wptr(struct amdgpu_device *adev,
0387                   struct amdgpu_ih_ring *ih)
0388 {
0389     u32 wptr, tmp;
0390     struct amdgpu_ih_regs *ih_regs;
0391 
0392     if (ih == &adev->irq.ih || ih == &adev->irq.ih_soft) {
0393         /* Only ring0 supports writeback. On other rings fall back
0394          * to register-based code with overflow checking below.
0395          * ih_soft ring doesn't have any backing hardware registers,
0396          * update wptr and return.
0397          */
0398         wptr = le32_to_cpu(*ih->wptr_cpu);
0399 
0400         if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
0401             goto out;
0402     }
0403 
0404     ih_regs = &ih->ih_regs;
0405 
0406     /* Double check that the overflow wasn't already cleared. */
0407     wptr = RREG32_NO_KIQ(ih_regs->ih_rb_wptr);
0408     if (!REG_GET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW))
0409         goto out;
0410 
0411     wptr = REG_SET_FIELD(wptr, IH_RB_WPTR, RB_OVERFLOW, 0);
0412 
0413     /* When a ring buffer overflow happen start parsing interrupt
0414      * from the last not overwritten vector (wptr + 32). Hopefully
0415      * this should allow us to catchup.
0416      */
0417     tmp = (wptr + 32) & ih->ptr_mask;
0418     dev_warn(adev->dev, "IH ring buffer overflow "
0419          "(0x%08X, 0x%08X, 0x%08X)\n",
0420          wptr, ih->rptr, tmp);
0421     ih->rptr = tmp;
0422 
0423     tmp = RREG32_NO_KIQ(ih_regs->ih_rb_cntl);
0424     tmp = REG_SET_FIELD(tmp, IH_RB_CNTL, WPTR_OVERFLOW_CLEAR, 1);
0425     WREG32_NO_KIQ(ih_regs->ih_rb_cntl, tmp);
0426 
0427 out:
0428     return (wptr & ih->ptr_mask);
0429 }
0430 
0431 /**
0432  * vega20_ih_irq_rearm - rearm IRQ if lost
0433  *
0434  * @adev: amdgpu_device pointer
0435  * @ih: amdgpu_ih_ring pointer
0436  *
0437  */
0438 static void vega20_ih_irq_rearm(struct amdgpu_device *adev,
0439                    struct amdgpu_ih_ring *ih)
0440 {
0441     uint32_t v = 0;
0442     uint32_t i = 0;
0443     struct amdgpu_ih_regs *ih_regs;
0444 
0445     ih_regs = &ih->ih_regs;
0446 
0447     /* Rearm IRQ / re-wwrite doorbell if doorbell write is lost */
0448     for (i = 0; i < MAX_REARM_RETRY; i++) {
0449         v = RREG32_NO_KIQ(ih_regs->ih_rb_rptr);
0450         if ((v < ih->ring_size) && (v != ih->rptr))
0451             WDOORBELL32(ih->doorbell_index, ih->rptr);
0452         else
0453             break;
0454     }
0455 }
0456 
0457 /**
0458  * vega20_ih_set_rptr - set the IH ring buffer rptr
0459  *
0460  * @adev: amdgpu_device pointer
0461  * @ih: amdgpu_ih_ring pointer
0462  *
0463  * Set the IH ring buffer rptr.
0464  */
0465 static void vega20_ih_set_rptr(struct amdgpu_device *adev,
0466                    struct amdgpu_ih_ring *ih)
0467 {
0468     struct amdgpu_ih_regs *ih_regs;
0469 
0470     if (ih == &adev->irq.ih_soft)
0471         return;
0472 
0473     if (ih->use_doorbell) {
0474         /* XXX check if swapping is necessary on BE */
0475         *ih->rptr_cpu = ih->rptr;
0476         WDOORBELL32(ih->doorbell_index, ih->rptr);
0477 
0478         if (amdgpu_sriov_vf(adev))
0479             vega20_ih_irq_rearm(adev, ih);
0480     } else {
0481         ih_regs = &ih->ih_regs;
0482         WREG32(ih_regs->ih_rb_rptr, ih->rptr);
0483     }
0484 }
0485 
0486 /**
0487  * vega20_ih_self_irq - dispatch work for ring 1 and 2
0488  *
0489  * @adev: amdgpu_device pointer
0490  * @source: irq source
0491  * @entry: IV with WPTR update
0492  *
0493  * Update the WPTR from the IV and schedule work to handle the entries.
0494  */
0495 static int vega20_ih_self_irq(struct amdgpu_device *adev,
0496                   struct amdgpu_irq_src *source,
0497                   struct amdgpu_iv_entry *entry)
0498 {
0499     switch (entry->ring_id) {
0500     case 1:
0501         schedule_work(&adev->irq.ih1_work);
0502         break;
0503     case 2:
0504         schedule_work(&adev->irq.ih2_work);
0505         break;
0506     default: break;
0507     }
0508     return 0;
0509 }
0510 
0511 static const struct amdgpu_irq_src_funcs vega20_ih_self_irq_funcs = {
0512     .process = vega20_ih_self_irq,
0513 };
0514 
0515 static void vega20_ih_set_self_irq_funcs(struct amdgpu_device *adev)
0516 {
0517     adev->irq.self_irq.num_types = 0;
0518     adev->irq.self_irq.funcs = &vega20_ih_self_irq_funcs;
0519 }
0520 
0521 static int vega20_ih_early_init(void *handle)
0522 {
0523     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0524 
0525     vega20_ih_set_interrupt_funcs(adev);
0526     vega20_ih_set_self_irq_funcs(adev);
0527     return 0;
0528 }
0529 
0530 static int vega20_ih_sw_init(void *handle)
0531 {
0532     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0533     int r;
0534 
0535     r = amdgpu_irq_add_id(adev, SOC15_IH_CLIENTID_IH, 0,
0536                   &adev->irq.self_irq);
0537     if (r)
0538         return r;
0539 
0540     r = amdgpu_ih_ring_init(adev, &adev->irq.ih, 256 * 1024, true);
0541     if (r)
0542         return r;
0543 
0544     adev->irq.ih.use_doorbell = true;
0545     adev->irq.ih.doorbell_index = adev->doorbell_index.ih << 1;
0546 
0547     r = amdgpu_ih_ring_init(adev, &adev->irq.ih1, PAGE_SIZE, true);
0548     if (r)
0549         return r;
0550 
0551     adev->irq.ih1.use_doorbell = true;
0552     adev->irq.ih1.doorbell_index = (adev->doorbell_index.ih + 1) << 1;
0553 
0554     r = amdgpu_ih_ring_init(adev, &adev->irq.ih2, PAGE_SIZE, true);
0555     if (r)
0556         return r;
0557 
0558     adev->irq.ih2.use_doorbell = true;
0559     adev->irq.ih2.doorbell_index = (adev->doorbell_index.ih + 2) << 1;
0560 
0561     /* initialize ih control registers offset */
0562     vega20_ih_init_register_offset(adev);
0563 
0564     r = amdgpu_ih_ring_init(adev, &adev->irq.ih_soft, PAGE_SIZE, true);
0565     if (r)
0566         return r;
0567 
0568     r = amdgpu_irq_init(adev);
0569 
0570     return r;
0571 }
0572 
0573 static int vega20_ih_sw_fini(void *handle)
0574 {
0575     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0576 
0577     amdgpu_irq_fini_sw(adev);
0578 
0579     return 0;
0580 }
0581 
0582 static int vega20_ih_hw_init(void *handle)
0583 {
0584     int r;
0585     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0586 
0587     r = vega20_ih_irq_init(adev);
0588     if (r)
0589         return r;
0590 
0591     return 0;
0592 }
0593 
0594 static int vega20_ih_hw_fini(void *handle)
0595 {
0596     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0597 
0598     vega20_ih_irq_disable(adev);
0599 
0600     return 0;
0601 }
0602 
0603 static int vega20_ih_suspend(void *handle)
0604 {
0605     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0606 
0607     return vega20_ih_hw_fini(adev);
0608 }
0609 
0610 static int vega20_ih_resume(void *handle)
0611 {
0612     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0613 
0614     return vega20_ih_hw_init(adev);
0615 }
0616 
0617 static bool vega20_ih_is_idle(void *handle)
0618 {
0619     /* todo */
0620     return true;
0621 }
0622 
0623 static int vega20_ih_wait_for_idle(void *handle)
0624 {
0625     /* todo */
0626     return -ETIMEDOUT;
0627 }
0628 
0629 static int vega20_ih_soft_reset(void *handle)
0630 {
0631     /* todo */
0632 
0633     return 0;
0634 }
0635 
0636 static void vega20_ih_update_clockgating_state(struct amdgpu_device *adev,
0637                            bool enable)
0638 {
0639     uint32_t data, def, field_val;
0640 
0641     if (adev->cg_flags & AMD_CG_SUPPORT_IH_CG) {
0642         def = data = RREG32_SOC15(OSSSYS, 0, mmIH_CLK_CTRL);
0643         field_val = enable ? 0 : 1;
0644         data = REG_SET_FIELD(data, IH_CLK_CTRL,
0645                      IH_RETRY_INT_CAM_MEM_CLK_SOFT_OVERRIDE, field_val);
0646         data = REG_SET_FIELD(data, IH_CLK_CTRL,
0647                      IH_BUFFER_MEM_CLK_SOFT_OVERRIDE, field_val);
0648         data = REG_SET_FIELD(data, IH_CLK_CTRL,
0649                      DBUS_MUX_CLK_SOFT_OVERRIDE, field_val);
0650         data = REG_SET_FIELD(data, IH_CLK_CTRL,
0651                      OSSSYS_SHARE_CLK_SOFT_OVERRIDE, field_val);
0652         data = REG_SET_FIELD(data, IH_CLK_CTRL,
0653                      LIMIT_SMN_CLK_SOFT_OVERRIDE, field_val);
0654         data = REG_SET_FIELD(data, IH_CLK_CTRL,
0655                      DYN_CLK_SOFT_OVERRIDE, field_val);
0656         data = REG_SET_FIELD(data, IH_CLK_CTRL,
0657                      REG_CLK_SOFT_OVERRIDE, field_val);
0658         if (def != data)
0659             WREG32_SOC15(OSSSYS, 0, mmIH_CLK_CTRL, data);
0660     }
0661 }
0662 
0663 static int vega20_ih_set_clockgating_state(void *handle,
0664                       enum amd_clockgating_state state)
0665 {
0666     struct amdgpu_device *adev = (struct amdgpu_device *)handle;
0667 
0668     vega20_ih_update_clockgating_state(adev,
0669                 state == AMD_CG_STATE_GATE);
0670     return 0;
0671 
0672 }
0673 
0674 static int vega20_ih_set_powergating_state(void *handle,
0675                       enum amd_powergating_state state)
0676 {
0677     return 0;
0678 }
0679 
0680 const struct amd_ip_funcs vega20_ih_ip_funcs = {
0681     .name = "vega20_ih",
0682     .early_init = vega20_ih_early_init,
0683     .late_init = NULL,
0684     .sw_init = vega20_ih_sw_init,
0685     .sw_fini = vega20_ih_sw_fini,
0686     .hw_init = vega20_ih_hw_init,
0687     .hw_fini = vega20_ih_hw_fini,
0688     .suspend = vega20_ih_suspend,
0689     .resume = vega20_ih_resume,
0690     .is_idle = vega20_ih_is_idle,
0691     .wait_for_idle = vega20_ih_wait_for_idle,
0692     .soft_reset = vega20_ih_soft_reset,
0693     .set_clockgating_state = vega20_ih_set_clockgating_state,
0694     .set_powergating_state = vega20_ih_set_powergating_state,
0695 };
0696 
0697 static const struct amdgpu_ih_funcs vega20_ih_funcs = {
0698     .get_wptr = vega20_ih_get_wptr,
0699     .decode_iv = amdgpu_ih_decode_iv_helper,
0700     .decode_iv_ts = amdgpu_ih_decode_iv_ts_helper,
0701     .set_rptr = vega20_ih_set_rptr
0702 };
0703 
0704 static void vega20_ih_set_interrupt_funcs(struct amdgpu_device *adev)
0705 {
0706     adev->irq.ih_funcs = &vega20_ih_funcs;
0707 }
0708 
0709 const struct amdgpu_ip_block_version vega20_ih_ip_block =
0710 {
0711     .type = AMD_IP_BLOCK_TYPE_IH,
0712     .major = 4,
0713     .minor = 2,
0714     .rev = 0,
0715     .funcs = &vega20_ih_ip_funcs,
0716 };